2009-01-21 13:36:26 +01:00
class Todo < ActiveRecord :: Base
2012-04-12 11:34:08 +02:00
before_save :render_note
2011-05-01 12:48:32 +02:00
after_save :save_predecessors
2012-04-08 22:10:43 +02:00
# associations
2012-08-27 21:00:51 +02:00
belongs_to :context , :touch = > true
belongs_to :project , :touch = > true
2009-01-21 13:36:26 +01:00
belongs_to :user
belongs_to :recurring_todo
2011-08-18 17:15:00 +02:00
2012-04-08 22:10:43 +02:00
# Tag association
include IsTaggable
2013-04-29 15:24:32 -05:00
2012-04-08 22:10:43 +02:00
# Dependencies associations
2009-06-08 23:43:40 +02:00
has_many :predecessor_dependencies , :foreign_key = > 'predecessor_id' , :class_name = > 'Dependency' , :dependent = > :destroy
has_many :successor_dependencies , :foreign_key = > 'successor_id' , :class_name = > 'Dependency' , :dependent = > :destroy
2009-06-09 13:45:39 +02:00
has_many :predecessors , :through = > :successor_dependencies
has_many :successors , :through = > :predecessor_dependencies
2009-05-20 13:00:14 +02:00
has_many :uncompleted_predecessors , :through = > :successor_dependencies ,
2011-02-04 20:11:42 +01:00
:source = > :predecessor , :conditions = > [ 'NOT (todos.state = ?)' , 'completed' ]
2009-06-08 23:43:40 +02:00
has_many :pending_successors , :through = > :predecessor_dependencies ,
2011-02-04 20:11:42 +01:00
:source = > :successor , :conditions = > [ 'todos.state = ?' , 'pending' ]
2013-04-29 15:24:32 -05:00
2011-05-01 12:48:32 +02:00
# scopes for states of this todo
2012-04-05 22:19:47 +02:00
scope :active , :conditions = > { :state = > 'active' }
scope :active_or_hidden , :conditions = > [ " todos.state = ? OR todos.state = ? " , 'active' , 'project_hidden' ]
scope :not_completed , :conditions = > [ 'NOT (todos.state = ?)' , 'completed' ]
2012-06-29 16:48:30 +02:00
scope :completed , :conditions = > [ " todos.state = ? " , 'completed' ]
scope :deferred , :conditions = > [ " todos.state = ? " , 'deferred' ]
2012-04-05 22:19:47 +02:00
scope :blocked , :conditions = > [ 'todos.state = ?' , 'pending' ]
scope :pending , :conditions = > [ 'todos.state = ?' , 'pending' ]
2012-06-29 16:48:30 +02:00
scope :deferred_or_blocked , :conditions = > [ " (todos.state = ?) OR (todos.state = ?) " , " deferred " , " pending " ]
scope :not_deferred_or_blocked , :conditions = > [ " (NOT todos.state=?) AND (NOT todos.state = ?) " , " deferred " , " pending " ]
2012-04-05 22:19:47 +02:00
scope :hidden ,
2011-10-28 19:33:51 +02:00
:joins = > " INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id " ,
2013-02-27 23:31:02 +01:00
:conditions = > [ " todos.state = ? OR (c_hidden.state = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?)) " ,
'project_hidden' , 'hidden' , 'active' , 'deferred' , 'pending' ]
2012-04-05 22:19:47 +02:00
scope :not_hidden ,
2011-10-28 19:33:51 +02:00
:joins = > " INNER JOIN contexts c_hidden ON c_hidden.id = todos.context_id " ,
2013-02-27 23:31:02 +01:00
:conditions = > [ 'NOT(todos.state = ? OR (c_hidden.state = ? AND (todos.state = ? OR todos.state = ? OR todos.state = ?)))' ,
'project_hidden' , 'hidden' , 'active' , 'deferred' , 'pending' ]
2009-01-21 13:36:26 +01:00
2011-05-01 12:48:32 +02:00
# other scopes
2012-04-05 22:19:47 +02:00
scope :are_due , :conditions = > [ 'NOT (todos.due IS NULL)' ]
2012-05-01 15:45:58 +02:00
scope :with_tag , lambda { | tag_id | joins ( " INNER JOIN taggings ON todos.id = taggings.taggable_id " ) . where ( " taggings.tag_id = ? " , tag_id ) }
scope :with_tags , lambda { | tag_ids | where ( " EXISTS(SELECT * from taggings t WHERE t.tag_id IN (?) AND t.taggable_id=todos.id AND t.taggable_type='Todo') " , tag_ids ) }
# scope :of_user, lambda { |user_id| {:conditions => ["todos.user_id = ? ", user_id] } }
2012-05-03 23:23:31 +02:00
scope :completed_after , lambda { | date | where ( " todos.completed_at > ? " , date ) }
scope :completed_before , lambda { | date | where ( " todos.completed_at < ? " , date ) }
scope :created_after , lambda { | date | where ( " todos.created_at > ? " , date ) }
scope :created_before , lambda { | date | where ( " todos.created_at < ? " , date ) }
2011-05-01 12:48:32 +02:00
2013-04-29 16:35:50 -05:00
scope :due_today , lambda { where ( " todos.due <= ? " , Time . zone . now ) }
def self . due_after ( date )
where ( 'todos.due > ?' , date )
end
def self . due_between ( start_date , end_date )
where ( 'todos.due > ? AND todos.due <= ?' , start_date , end_date )
end
2009-01-21 13:36:26 +01:00
STARRED_TAG_NAME = " starred "
2011-06-17 14:58:32 +02:00
DEFAULT_INCLUDES = [ :project , :context , :tags , :taggings , :pending_successors , :uncompleted_predecessors , :recurring_todo ]
2010-08-12 14:39:58 +02:00
2011-09-30 12:06:43 +02:00
# state machine
2011-05-16 15:42:47 +08:00
include AASM
2011-06-12 04:29:35 +02:00
aasm_initial_state Proc . new { | t | ( t . show_from && t . user && ( t . show_from > t . user . date ) ) ? :deferred : :active }
2011-08-18 17:15:00 +02:00
2013-04-29 15:24:32 -05:00
aasm :column = > :state do
2009-01-21 13:36:26 +01:00
2013-05-03 19:28:26 +02:00
state :active #, :enter => Proc.new{|t| puts "$$$ activating #{t.aasm_current_state} - #{t.show_from} "}
2013-04-29 11:53:32 +02:00
state :project_hidden
2013-05-03 19:28:26 +02:00
state :completed , :before_enter = > Proc . new { | t | t . completed_at = Time . zone . now } , :before_exit = > Proc . new { | t | t . completed_at = nil }
state :deferred , :after_exit = > Proc . new { | t | t [ :show_from ] = nil }
2013-04-29 11:53:32 +02:00
state :pending
2011-08-18 17:15:00 +02:00
2013-04-29 11:53:32 +02:00
event :defer do
transitions :to = > :deferred , :from = > [ :active ]
end
2011-08-18 17:15:00 +02:00
2013-04-29 11:53:32 +02:00
event :complete do
transitions :to = > :completed , :from = > [ :active , :project_hidden , :deferred , :pending ]
end
2011-08-18 17:15:00 +02:00
2013-04-29 11:53:32 +02:00
event :activate do
transitions :to = > :active , :from = > [ :project_hidden , :deferred ]
transitions :to = > :active , :from = > [ :completed ] , :guard = > :no_uncompleted_predecessors?
transitions :to = > :active , :from = > [ :pending ] , :guard = > :no_uncompleted_predecessors_or_deferral?
transitions :to = > :pending , :from = > [ :completed ] , :guard = > :uncompleted_predecessors?
transitions :to = > :deferred , :from = > [ :pending ] , :guard = > :no_uncompleted_predecessors?
end
2011-08-18 17:15:00 +02:00
2013-04-29 11:53:32 +02:00
event :hide do
transitions :to = > :project_hidden , :from = > [ :active , :deferred , :pending ]
end
2011-08-18 17:15:00 +02:00
2013-04-29 11:53:32 +02:00
event :unhide do
transitions :to = > :deferred , :from = > [ :project_hidden ] , :guard = > Proc . new { | t | ! t . show_from . blank? }
transitions :to = > :pending , :from = > [ :project_hidden ] , :guard = > :uncompleted_predecessors?
transitions :to = > :active , :from = > [ :project_hidden ]
end
event :block do
transitions :to = > :pending , :from = > [ :active , :deferred ]
end
2009-05-20 02:05:49 +02:00
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
attr_protected :user
# Description field can't be empty, and must be < 100 bytes Notes must be <
# 60,000 bytes (65,000 actually, but I'm being cautious)
validates_presence_of :description
validates_length_of :description , :maximum = > 100
2011-08-18 17:15:00 +02:00
validates_length_of :notes , :maximum = > 60000 , :allow_nil = > true
2009-01-21 13:36:26 +01:00
validates_presence_of :show_from , :if = > :deferred?
validates_presence_of :context
2012-04-17 16:47:37 +02:00
validate :check_show_from_in_future
validate :check_circular_dependencies
2011-08-18 17:15:00 +02:00
2012-04-17 16:47:37 +02:00
def check_show_from_in_future
2012-08-26 17:33:51 +02:00
if show_from_changed? # only check on change of show_from
if ! show_from . blank? && ( show_from < user . date )
errors . add ( " show_from " , I18n . t ( 'models.todo.error_date_must_be_future' ) )
end
2012-04-17 16:47:37 +02:00
end
end
2013-04-29 15:24:32 -05:00
2012-04-17 16:47:37 +02:00
def check_circular_dependencies
unless @predecessor_array . nil? # Only validate predecessors if they changed
@predecessor_array . each do | todo |
errors . add ( " Depends on: " , " Adding ' #{ todo . specification } ' would create a circular dependency " ) if is_successor? ( todo )
end
end
end
2013-04-29 15:24:32 -05:00
2009-06-30 23:17:33 +02:00
def initialize ( * args )
super ( * args )
2009-07-19 21:46:45 +02:00
@predecessor_array = nil # Used for deferred save of predecessors
2011-02-03 16:59:59 +01:00
@removed_predecessors = nil
2009-06-30 23:17:33 +02:00
end
2011-08-18 17:15:00 +02:00
2009-08-16 22:00:20 +02:00
def no_uncompleted_predecessors_or_deferral?
2011-08-18 17:15:00 +02:00
no_deferral = show_from . blank? or Time . zone . now > show_from
2011-11-16 19:36:09 +01:00
return ( no_deferral && no_uncompleted_predecessors? )
2009-08-16 22:00:20 +02:00
end
2011-08-18 17:15:00 +02:00
2009-08-16 22:00:20 +02:00
def no_uncompleted_predecessors?
2011-11-16 19:36:09 +01:00
return ! uncompleted_predecessors?
2009-08-19 22:15:38 +02:00
end
2011-08-18 17:15:00 +02:00
def uncompleted_predecessors?
2012-04-17 16:47:37 +02:00
return ! uncompleted_predecessors . all . empty?
2011-08-18 17:15:00 +02:00
end
2013-04-29 15:15:48 +02:00
def should_be_blocked?
return ! ( uncompleted_predecessors . empty? || state == 'project_hidden' )
end
2009-08-20 09:54:22 +02:00
# Returns a string with description <context, project>
def specification
2011-02-12 10:38:15 +01:00
project_name = self . project . is_a? ( NullProject ) ? " (none) " : self . project . name
return " \' #{ self . description } \' < \' #{ self . context . title } \' ; \' #{ project_name } \' > "
2009-08-20 09:54:22 +02:00
end
2011-08-18 17:15:00 +02:00
2009-06-30 23:17:33 +02:00
def save_predecessors
2009-07-19 21:46:45 +02:00
unless @predecessor_array . nil? # Only save predecessors if they changed
2011-02-12 10:38:15 +01:00
current_array = self . predecessors
2009-07-19 21:46:45 +02:00
remove_array = current_array - @predecessor_array
add_array = @predecessor_array - current_array
2011-02-03 16:59:59 +01:00
@removed_predecessors = [ ]
2011-02-12 10:38:15 +01:00
remove_array . each do | todo |
unless todo . nil?
@removed_predecessors << todo
self . predecessors . delete ( todo )
2011-02-03 16:59:59 +01:00
end
2009-07-19 21:46:45 +02:00
end
2011-02-12 10:38:15 +01:00
add_array . each do | todo |
unless todo . nil?
self . predecessors << todo unless self . predecessors . include? ( todo )
2009-07-19 21:46:45 +02:00
else
2011-02-12 10:38:15 +01:00
logger . error " Could not find #{ todo . description } " # Unexpected since validation passed
2009-07-19 21:46:45 +02:00
end
2009-06-30 23:17:33 +02:00
end
2011-08-18 17:15:00 +02:00
end
2011-02-03 16:59:59 +01:00
end
2013-02-17 17:37:15 +01:00
def touch_predecessors
self . touch
predecessors . each { | p | p . touch_predecessors }
end
2011-02-03 16:59:59 +01:00
def removed_predecessors
return @removed_predecessors
2009-06-30 23:17:33 +02:00
end
2011-08-18 17:15:00 +02:00
2012-04-08 14:52:44 +02:00
# remove predecessor and activate myself if it was the last predecessor
2009-11-10 22:15:16 -05:00
def remove_predecessor ( predecessor )
2011-02-12 10:38:15 +01:00
self . predecessors . delete ( predecessor )
2012-04-08 14:52:44 +02:00
if self . predecessors . empty?
self . activate!
else
save!
end
2009-11-10 22:15:16 -05:00
end
2011-08-18 17:15:00 +02:00
2009-06-30 23:17:33 +02:00
# Returns true if t is equal to self or a successor of self
2011-02-12 10:38:15 +01:00
def is_successor? ( todo )
if self == todo
2009-06-30 23:17:33 +02:00
return true
elsif self . successors . empty?
return false
else
self . successors . each do | item |
2011-02-12 10:38:15 +01:00
if item . is_successor? ( todo )
2009-06-30 23:17:33 +02:00
return true
end
end
end
return false
2009-01-21 13:36:26 +01:00
end
2011-08-18 17:15:00 +02:00
2011-06-17 13:33:54 +02:00
def has_pending_successors
2011-06-17 14:58:32 +02:00
return ! pending_successors . empty?
2011-06-17 13:33:54 +02:00
end
2011-08-18 17:15:00 +02:00
2011-01-01 18:55:53 +01:00
def hidden?
2012-12-16 15:20:43 +01:00
return self . project_hidden? || ( self . context . hidden? && ( self . active? || self . deferred? ) )
2011-01-01 18:55:53 +01:00
end
2009-01-21 13:36:26 +01:00
def update_state_from_project
2012-07-18 11:42:26 +02:00
if self . project_hidden? && ( ! self . project . hidden? )
2009-11-04 22:45:38 -05:00
if self . uncompleted_predecessors . empty?
2012-07-15 21:28:42 +02:00
self . activate!
2009-11-25 16:13:52 -05:00
else
2012-07-15 21:28:42 +02:00
self . block!
2009-11-04 22:45:38 -05:00
end
2012-07-18 11:42:26 +02:00
elsif self . active? && self . project . hidden?
2012-07-15 21:28:42 +02:00
self . hide!
2009-01-21 13:36:26 +01:00
end
2011-01-06 23:01:17 +01:00
self . save!
2009-01-21 13:36:26 +01:00
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
def toggle_completion!
2011-06-21 11:03:23 +02:00
return completed? ? activate! : complete!
2009-01-21 13:36:26 +01:00
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
def show_from
self [ :show_from ]
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
def show_from = ( date )
2013-05-03 19:28:26 +02:00
if deferred? && date . blank?
activate
else
# parse Date objects into the proper timezone
date = user . at_midnight ( date ) if ( date . is_a? Date )
2011-06-12 04:29:35 +02:00
2013-05-03 19:28:26 +02:00
# show_from needs to be set before state_change because of "bug" in aasm.
# If show_from is not set, the todo will not validate and thus aasm will not save
# (see http://stackoverflow.com/questions/682920/persisting-the-state-column-on-transition-using-rubyist-aasm-acts-as-state-machi)
self [ :show_from ] = date
2011-06-10 14:28:42 +02:00
2013-05-04 13:44:45 +02:00
defer if active? && ! date . blank? && show_from > user . date
2013-05-03 19:28:26 +02:00
end
2009-01-21 13:36:26 +01:00
end
def starred?
2011-11-16 19:36:09 +01:00
return has_tag? ( STARRED_TAG_NAME )
2009-01-21 13:36:26 +01:00
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
def toggle_star!
2011-08-04 23:14:29 +02:00
self . starred = ! starred?
2011-07-30 18:52:11 +02:00
end
def starred = ( starred )
if starred
2011-08-04 23:14:29 +02:00
_add_tags STARRED_TAG_NAME unless starred?
2011-07-30 18:52:11 +02:00
else
_remove_tags STARRED_TAG_NAME
end
starred
2009-01-21 13:36:26 +01:00
end
def from_recurring_todo?
return self . recurring_todo_id != nil
end
2009-08-20 09:54:22 +02:00
2009-11-04 22:39:19 -05:00
def add_predecessor_list ( predecessor_list )
2009-08-21 14:59:03 +02:00
return unless predecessor_list . kind_of? String
2011-02-12 10:38:15 +01:00
2011-11-16 19:36:09 +01:00
@predecessor_array = predecessor_list . split ( " , " ) . inject ( [ ] ) do | list , todo_id |
2013-02-27 11:50:49 +01:00
predecessor = self . user . todos . find ( todo_id . to_i ) unless todo_id . blank?
2011-11-16 19:36:09 +01:00
list << predecessor unless predecessor . nil?
list
2011-02-12 10:38:15 +01:00
end
2010-08-12 14:39:58 +02:00
return @predecessor_array
2009-11-04 22:39:19 -05:00
end
2011-08-18 17:15:00 +02:00
2009-06-30 23:51:41 +02:00
def add_predecessor ( t )
2011-10-10 22:25:51 +02:00
return if t . nil?
2011-11-16 16:37:04 +01:00
2011-02-12 10:38:15 +01:00
@predecessor_array = predecessors
2011-02-12 23:18:00 +01:00
@predecessor_array << t
2009-06-30 23:51:41 +02:00
end
2011-08-18 17:15:00 +02:00
2011-06-21 11:03:23 +02:00
# activate todos that should be activated if the current todo is completed
def activate_pending_todos
2012-04-18 14:22:58 +02:00
pending_todos = successors . select { | t | t . uncompleted_predecessors . empty? }
2011-06-21 11:03:23 +02:00
pending_todos . each { | t | t . activate! }
return pending_todos
2009-11-10 22:10:52 -05:00
end
2011-08-18 17:15:00 +02:00
2009-11-10 22:10:52 -05:00
# Return todos that should be blocked if the current todo is undone
2011-06-21 11:03:23 +02:00
def block_successors
2012-04-18 14:22:58 +02:00
active_successors = successors . select { | t | t . active? or t . deferred? }
2011-06-21 11:03:23 +02:00
active_successors . each { | t | t . block! }
return active_successors
2009-11-10 22:10:52 -05:00
end
2010-04-07 10:06:46 -04:00
def raw_notes = ( value )
self [ :notes ] = value
end
2011-11-16 16:37:04 +01:00
2011-10-10 22:25:51 +02:00
# XML API fixups
def predecessor_dependencies = ( params )
2012-04-08 16:01:29 +02:00
deps = params [ :predecessor ]
return if deps . nil?
2011-11-16 16:37:04 +01:00
2011-11-20 14:48:49 +01:00
# for multiple dependencies, value will be an array of id's, but for a single dependency,
# value will be a string. In that case convert to array
2012-04-08 16:01:29 +02:00
deps = [ deps ] unless deps . class == Array
2011-11-20 14:48:49 +01:00
2013-02-27 11:50:49 +01:00
deps . each { | dep | self . add_predecessor ( self . user . todos . find ( dep . to_i ) ) unless dep . blank? }
2011-10-10 22:25:51 +02:00
end
2011-11-16 16:37:04 +01:00
2011-10-10 22:25:51 +02:00
alias_method :original_context = , :context =
def context = ( value )
if value . is_a? Context
self . original_context = ( value )
else
2013-02-27 11:50:49 +01:00
c = Context . where ( :name = > value [ :name ] ) . first
2011-11-21 15:24:29 +01:00
c = Context . create ( value ) if c . nil?
self . original_context = ( c )
2011-10-10 22:25:51 +02:00
end
end
2011-11-16 16:37:04 +01:00
2011-11-16 19:36:09 +01:00
alias_method :original_project , :project
def project
original_project . nil? ? Project . null_object : original_project
end
2011-10-10 22:25:51 +02:00
alias_method :original_project = , :project =
def project = ( value )
if value . is_a? Project
self . original_project = ( value )
2011-11-21 15:24:29 +01:00
elsif ! ( value . nil? || value . is_a? ( NullProject ) )
2013-02-27 11:50:49 +01:00
p = Project . where ( :name = > value [ :name ] ) . first
2011-11-21 15:24:29 +01:00
p = Project . create ( value ) if p . nil?
self . original_project = ( p )
2011-11-16 19:36:09 +01:00
else
self . original_project = value
2011-10-10 22:25:51 +02:00
end
end
2011-11-16 16:37:04 +01:00
2013-05-03 21:54:03 +02:00
def has_project?
return ! ( project_id . nil? || project . is_a? ( NullProject ) )
end
2011-11-16 16:37:04 +01:00
# used by the REST API. <tags> will also work, this is renamed to add_tags in TodosController::TodoCreateParamsHelper::initialize
def add_tags = ( params )
2012-03-19 20:04:56 +01:00
unless params [ :tag ] . nil?
tag_list = params [ :tag ] . inject ( [ ] ) { | list , value | list << value [ :name ] }
tag_with tag_list . join ( " , " )
end
2011-10-10 22:25:51 +02:00
end
2011-08-18 17:15:00 +02:00
2011-11-16 16:37:04 +01:00
# Rich Todo API
2009-01-21 13:36:26 +01:00
def self . from_rich_message ( user , default_context_id , description , notes )
fields = description . match ( / ([^>@]*)@?([^>]*)>?(.*) / )
description = fields [ 1 ] . strip
context = fields [ 2 ] . strip
project = fields [ 3 ] . strip
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
context = nil if context == " "
project = nil if project == " "
context_id = default_context_id
unless ( context . nil? )
2012-04-24 20:47:07 +02:00
found_context = user . contexts . active . where ( " name like ? " , " % #{ context } % " ) . first
found_context = user . contexts . where ( " name like ? " , " % #{ context } % " ) . first if ! found_context
context_id = found_context . id if found_context
2009-01-21 13:36:26 +01:00
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
unless user . contexts . exists? context_id
raise ( CannotAccessContext , " Cannot access a context that does not belong to this user. " )
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
project_id = nil
unless ( project . blank? )
if ( project [ 0 .. 3 ] . downcase == " new: " )
found_project = user . projects . build
found_project . name = project [ 4 .. 255 + 4 ] . strip
found_project . save!
else
2011-05-01 12:48:32 +02:00
found_project = user . projects . active . find_by_namepart ( project )
2009-01-21 13:36:26 +01:00
found_project = user . projects . find_by_namepart ( project ) if found_project . nil?
end
project_id = found_project . id unless found_project . nil?
end
2011-08-18 17:15:00 +02:00
2009-01-21 13:36:26 +01:00
todo = user . todos . build
todo . description = description
2010-04-07 10:06:46 -04:00
todo . raw_notes = notes
2009-01-21 13:36:26 +01:00
todo . context_id = context_id
todo . project_id = project_id unless project_id . nil?
return todo
end
2011-08-18 17:15:00 +02:00
2012-04-12 11:34:08 +02:00
def render_note
2012-04-12 12:47:25 +02:00
unless self . notes . nil?
2012-04-12 20:05:57 +02:00
self . rendered_notes = Tracks :: Utils . render_text ( self . notes )
2012-04-12 11:34:08 +02:00
else
2012-04-12 12:47:25 +02:00
self . rendered_notes = nil
2012-04-12 11:34:08 +02:00
end
end
2013-04-29 15:24:32 -05:00
2009-01-21 13:36:26 +01:00
end