From 12c98077ee7b346ae72d8da65c76425d4f38e0ea Mon Sep 17 00:00:00 2001
From: Coleman The following errors prevented the model from being saved:
')
+ end
+
+ def error_messages_for(obj)
+ obj = instance_variable_get("@#{obj.to_s}") if obj.is_a?(Symbol)
+ return nil if obj.errors.nil? or obj.errors.empty?
+ res = []
+ res << ""
+ obj.errors.each do |field, msg|
+ res << "
"
+ res << "
"
+ res.join
+ end
+
+ def show_page_description(page)
+ page_cache = Cache.get(page.cache_name)
+ if page_cache.nil?
+ redcloth_opts = [
+ :textile,
+ :block_textile_prefix,
+ :block_textile_lists,
+ :inline_textile_code,
+ :inline_textile_link,
+ :inline_textile_image,
+ :inline_textile_span,
+ :glyphs_textile
+ ]
+ desc = h(page.description.to_s).to_s.gsub(/\"\;/, '"')
+ # i need pre/code block together... because i code :)
+ desc.gsub!("<pre><code>", "
")
+ rc = RedCloth.new(desc)
+ rc.no_span_caps = true
+ rc.filter_styles = true
+ page_cache = rc.to_html(redcloth_opts).gsub(Page.wiki_word_pattern) do |match|
+ pg_name = $1
+ if Page.exists?(pg_name)
+ "#{pg_name}"
+ else
+ "#{pg_name}?"
+ end
+ end
+ Cache.put(page.cache_name, page_cache)
+ end
+ page_cache
+ end
+
+ def show_page_link(page)
+ "#{page.name}"
+ end
+
+ def tag_cloud(tags)
+ max = 0
+ tags.each { |tag| max = tag.count.to_i if tag.count.to_i > max }
+ min = max
+ tags.each { |tag| min = tag.count.to_i if tag.count.to_i < min }
+ divisor = ((max - min) / tag_cloud_styles.size) + 1
+ tags.collect { |t| "#{t.name}" }.join(' ')
+ end
+
+ def tag_cloud_styles
+ %w(tag_cloud_1 tag_cloud_2 tag_cloud_3 tag_cloud_4 tag_cloud_5 tag_cloud_6 tag_cloud_7 tag_cloud_8 tag_cloud_9 tag_cloud_10 tag_cloud_11 tag_cloud_12)
+ end
+
+ def allowed_to?(name, obj = nil)
+ return false if session[:author_id].nil?
+ @author_for_permissions ||= Author.find(session[:author_id])
+ has_base = Permission.author_has_permission_to?(name, @author_for_permissions)
+ if obj and obj.respond_to?('author_id') and obj.author_id != session[:author_id]
+ has_base and Permission.author_has_permission_to?("any_#{name}", @author_for_permissions)
+ else
+ has_base
+ end
+ end
+
+ def block_to_partial(partial_name, options = {}, &block)
+ options.merge!(:body => capture(&block))
+ concat(partial(partial_name, :locals => options), block.binding)
+ end
+
+ def photo_url(photo)
+ "/photos/#{photo.id}/#{photo.filename}"
+ end
+
+ def screen_photo_url(photo)
+ url(:controller => 'photos', :action => 'screen', :id => photo.id)
+ end
+
+ def thumbnail_photo_url(photo)
+ url(:controller => 'photos', :action => 'thumbnail', :id => photo.id)
+ end
+
+ def indicator
+ ""
+ end
+ end
+end
diff --git a/app/helpers/invitations_helper.rb b/app/helpers/invitations_helper.rb
new file mode 100644
index 0000000..ddb78cd
--- /dev/null
+++ b/app/helpers/invitations_helper.rb
@@ -0,0 +1,5 @@
+module Merb
+ module InvitationsHelper
+
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/news_helper.rb b/app/helpers/news_helper.rb
new file mode 100644
index 0000000..3a083eb
--- /dev/null
+++ b/app/helpers/news_helper.rb
@@ -0,0 +1,4 @@
+module Merb
+ module NewsHelper
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/pages_helper.rb b/app/helpers/pages_helper.rb
new file mode 100644
index 0000000..47ec031
--- /dev/null
+++ b/app/helpers/pages_helper.rb
@@ -0,0 +1,7 @@
+module Merb
+ module PagesHelper
+ def edit_page_link(page)
+ "#{h(page.name)}"
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/permissions_helper.rb b/app/helpers/permissions_helper.rb
new file mode 100644
index 0000000..046b042
--- /dev/null
+++ b/app/helpers/permissions_helper.rb
@@ -0,0 +1,5 @@
+module Merb
+ module PermissionsHelper
+
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/photo_tags_helper.rb b/app/helpers/photo_tags_helper.rb
new file mode 100644
index 0000000..c82313d
--- /dev/null
+++ b/app/helpers/photo_tags_helper.rb
@@ -0,0 +1,5 @@
+module Merb
+ module PhotoTagsHelper
+
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/photos_helper.rb b/app/helpers/photos_helper.rb
new file mode 100644
index 0000000..cb0c3c6
--- /dev/null
+++ b/app/helpers/photos_helper.rb
@@ -0,0 +1,5 @@
+module Merb
+ module PhotosHelper
+
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
new file mode 100644
index 0000000..747bdd1
--- /dev/null
+++ b/app/helpers/sessions_helper.rb
@@ -0,0 +1,5 @@
+module Merb
+ module SessionsHelper
+
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb
new file mode 100644
index 0000000..9fb6115
--- /dev/null
+++ b/app/helpers/tags_helper.rb
@@ -0,0 +1,12 @@
+module Merb
+ module TagsHelper
+ def highlight(text, phrase)
+ if text.blank? || phrase.blank?
+ text
+ else
+ match = Array(phrase).map { |p| Regexp.escape(p) }.join('|')
+ text.gsub(/(#{match})/i, '\1')
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/models/album.rb b/app/models/album.rb
new file mode 100644
index 0000000..385f9a6
--- /dev/null
+++ b/app/models/album.rb
@@ -0,0 +1,46 @@
+class Album < ActiveRecord::Base
+ validates_presence_of :name
+ validates_uniqueness_of :name
+ validates_format_of :name, :with => /^[\w ]+$/
+ has_and_belongs_to_many :tags, :order => 'tags.name ASC'
+ has_many :photos
+ after_create :save_tags
+
+ def tag_names
+ self.tags.collect { |t| t.name }.join(' ')
+ end
+
+ def tag_names=(newtags)
+ tag_name_ary = newtags.split if newtags.is_a?(String)
+ tag_name_ary ||= newtags
+ new_tags = []
+ tag_name_ary.each do |tname|
+ t = Tag.find_by_name tname
+ t ||= Tag.create :name => tname
+ new_tags << t
+ end
+ self.tags = new_tags
+ end
+
+ def album_thumbnail
+ self.photos.first
+ end
+
+ def self.for_select
+ self.find(:all, :select => 'name', :order => 'name ASC').collect do |a|
+ a.name
+ end
+ end
+
+ def self.popular_tags(limit = nil)
+ query = "SELECT tags.id, tags.name, count(*) AS count FROM albums_tags, tags, albums WHERE tags.id = tag_id AND albums_tags.album_id = albums.id GROUP BY tags.id, tags.name ORDER BY tags.name ASC"
+ query << " LIMIT #{limit}" unless limit.nil?
+ Tag.find_by_sql(query)
+ end
+
+ protected
+
+ def save_tags
+ self.tags.each { |x| x.save }
+ end
+end
\ No newline at end of file
diff --git a/app/models/author.rb b/app/models/author.rb
new file mode 100644
index 0000000..1d41048
--- /dev/null
+++ b/app/models/author.rb
@@ -0,0 +1,45 @@
+require 'digest/sha1'
+
+class Author < ActiveRecord::Base
+ validates_uniqueness_of :name
+ validates_presence_of :name
+ validates_format_of :name, :with => /^\w+$/
+
+ attr_accessor :password, :password_confirmation
+ attr_protected :encrypted_password, :salt
+
+ has_and_belongs_to_many :permissions
+ has_many :pages
+
+ before_save :encrypt_password
+
+ def self.authenticate(username, password)
+ user = self.find_by_name(username)
+ return nil if user.nil?
+ user.matches_password?(password) ? user : nil
+ end
+
+ def matches_password?(cleartext_password)
+ self.encrypted_password == Digest::SHA1.hexdigest("---#{cleartext_password}---#{self.salt}---")
+ end
+
+ protected
+
+ def encrypt_password
+ skip = false
+ if self.password.to_s.empty? or self.password_confirmation.to_s.empty?
+ if self.encrypted_password.to_s.empty?
+ self.errors.add(:password, 'cannot be blank')
+ else
+ skip = true
+ end
+ elsif self.password != self.password_confirmation
+ self.errors.add(:passwords, 'do not match')
+ end
+ return false unless self.errors.empty?
+ return if skip
+ self.salt = Digest::SHA1.hexdigest("---#{Time.now}---#{rand.to_s}---")
+ self.encrypted_password = Digest::SHA1.hexdigest("---#{self.password}---#{self.salt}---")
+ self.encrypted_password
+ end
+end
\ No newline at end of file
diff --git a/app/models/comment.rb b/app/models/comment.rb
new file mode 100644
index 0000000..9db5c45
--- /dev/null
+++ b/app/models/comment.rb
@@ -0,0 +1,12 @@
+class Comment < ActiveRecord::Base
+ belongs_to :page
+ belongs_to :author
+
+ def name
+ if self.author
+ self.author.name
+ else
+ self.user
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/models/invitation.rb b/app/models/invitation.rb
new file mode 100644
index 0000000..a5d52ee
--- /dev/null
+++ b/app/models/invitation.rb
@@ -0,0 +1,19 @@
+class Invitation < ActiveRecord::Base
+ before_create :set_invitation_code
+ validates_presence_of :recipient
+ validates_format_of :recipient, :with => /^.+\@.+\.\w{2,3}$/,
+ :message => 'appears to be a fake'
+ attr_accessor :recipient
+
+ protected
+
+ def set_invitation_code
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
+ check = nil
+ begin
+ check = ''
+ 1.upto(32) { |k| check << chars[rand(chars.size - 1)] }
+ end while Invitation.find_by_code(check)
+ self.code = check
+ end
+end
\ No newline at end of file
diff --git a/app/models/page.rb b/app/models/page.rb
new file mode 100644
index 0000000..f1fe242
--- /dev/null
+++ b/app/models/page.rb
@@ -0,0 +1,69 @@
+class Page < ActiveRecord::Base
+ validates_format_of :name, :with => /^[\w ]+$/
+ validates_uniqueness_of :name
+ validates_format_of :department, :with => /^[\w]+$/, :allow_nil => true, :allow_blank => true
+
+ has_many :comments, :order => 'created_at ASC'
+ has_and_belongs_to_many :tags, :order => 'tags.name ASC'
+ belongs_to :author
+ attr_protected :author_id
+ has_and_belongs_to_many :pages, :join_table => 'wiki_words', :foreign_key => :source_id, :class_name => 'Page', :association_foreign_key => :destination_id
+ has_and_belongs_to_many :pages_that_link_to_me, :join_table => 'wiki_words', :foreign_key => :destination_id, :association_foreign_key => :source_id, :class_name => 'Page'
+
+ before_create :set_author_id
+ after_save :update_wiki_words
+ after_save :destroy_cache
+
+ def self.exists?(name)
+ !self.find_by_name(name).nil?
+ end
+
+ def tag_names
+ self.tags.collect { |t| t.name }.join(' ')
+ end
+
+ def tag_names=(newtags)
+ tag_name_ary = newtags.split if newtags.is_a?(String)
+ tag_name_ary ||= newtags
+ new_tags = []
+ tag_name_ary.each do |tname|
+ t = Tag.find_by_name tname
+ t ||= Tag.create :name => tname
+ new_tags << t
+ end
+ self.tags = new_tags
+ end
+
+ def self.popular_tags(limit = nil)
+ query = "SELECT tags.id, tags.name, count(*) AS count FROM pages_tags, tags, pages WHERE tags.id = tag_id AND pages_tags.page_id = pages.id GROUP BY tags.id, tags.name ORDER BY tags.name ASC"
+ query << " LIMIT #{limit}" unless limit.nil?
+ Tag.find_by_sql(query)
+ end
+
+ def cache_name
+ "RedCloth_#{self.id}"
+ end
+
+ def self.wiki_word_pattern
+ /\[\[([A-Za-z0-9 ]+)\]\]/
+ end
+
+ protected
+
+ def set_author_id
+ self.author_id ||= Application.current_author_id
+ end
+
+ def update_wiki_words
+ self.pages.clear
+ self.description.gsub(Page.wiki_word_pattern) do |match|
+ p = Page.find_by_name($1) rescue nil
+ WikiWord.create :source_id => self.id, :destination_id => p.id if p
+ end
+ end
+
+ def destroy_cache
+ Cache.delete(self.cache_name)
+ self.pages_that_link_to_me.each { |p| Cache.delete(p.cache_name) }
+ end
+end
diff --git a/app/models/permission.rb b/app/models/permission.rb
new file mode 100644
index 0000000..e167db0
--- /dev/null
+++ b/app/models/permission.rb
@@ -0,0 +1,12 @@
+class Permission < ActiveRecord::Base
+ has_and_belongs_to_many :authors
+
+ validates_presence_of :name
+ validates_uniqueness_of :name
+
+ def self.author_has_permission_to?(name, author = nil)
+ p = self.find_by_name(name.to_s)
+ p ||= self.create :name => name.to_s # auto-create permission if necessary
+ p.authors.include?(author)
+ end
+end
\ No newline at end of file
diff --git a/app/models/photo.rb b/app/models/photo.rb
new file mode 100644
index 0000000..cd29314
--- /dev/null
+++ b/app/models/photo.rb
@@ -0,0 +1,97 @@
+class Photo < ActiveRecord::Base
+ attr_accessor :file
+
+ validates_presence_of :author_id, :album_id
+
+ belongs_to :album
+ belongs_to :author
+ has_many :photo_tags, :dependent => :destroy
+ has_many :tags, :through => :photo_tags
+
+ before_validation_on_create :set_author_id
+ before_create :validate_image_sanity
+ after_create :create_directories
+ before_destroy :destroy_directories
+
+ attr_protected :author_id
+
+ ##
+ # Determines the base directory for all files in this model.
+ #
+ def base_directory
+ "#{Merb.root}/public/photos/#{id}"
+ end
+
+ def self.popular_tags(limit = nil)
+ query = "SELECT tags.id, tags.name, count(*) AS count FROM photo_tags, tags, photos WHERE tags.id = tag_id AND photo_tags.photo_id = photos.id GROUP BY tags.id, tags.name ORDER BY tags.name ASC"
+ query << " LIMIT #{limit}" unless limit.nil?
+ Tag.find_by_sql(query)
+ end
+
+ protected
+
+ ##
+ # Sets the Author marker for ownership on creation.
+ #
+ def set_author_id
+ self.author_id ||= Application.current_author_id
+ end
+
+ ##
+ # Checks to make sure that the file exists and is an image.
+ #
+ def validate_image_sanity
+ if self.file[:tempfile].nil?
+ self.errors.add(:file, 'File is not a file')
+ end
+ if self.file[:content_type] !~ /image\/\w+/
+ self.errors.add(:file, 'File is not a supported type')
+ end
+ if self.file[:size] > 3 * 1048576
+ self.errors.add(:file, 'File is too big (3MB max)')
+ end
+ return false unless self.errors.empty?
+
+ begin
+ @fstr = self.file[:tempfile].read
+ iary = Magick::Image.from_blob(@fstr)
+ self.filename = File.basename(self.file[:filename]).gsub(/[^\w._-]/, '')
+ if iary.first.to_s =~ / (\d+)x(\d+) /
+ self.width = $1
+ self.height = $2
+ end
+ rescue
+ $stderr.puts("Caught an exception saving an image:")
+ $stderr.puts("* #{$!}")
+ self.errors.add(:file, 'File could not be read as an image')
+ return false
+ end
+
+ self.content_type = self.file[:content_type]
+ true
+ end
+
+ ##
+ # Makes the directories and writes the file to disk.
+ #
+ def create_directories
+ File.umask(0022)
+ Dir.mkdir(base_directory) unless File.exist?(base_directory)
+ File.open("#{base_directory}/#{self.filename}", "w") do |f|
+ f.puts(@fstr)
+ end
+ File.chmod(0644, "#{base_directory}/#{self.filename}")
+ end
+
+ ##
+ # Removes the directories and files associated with this model on destroy.
+ #
+ def destroy_directories
+ return unless File.exists?(base_directory)
+ Dir.foreach(base_directory) do |file|
+ next if file =~ /^\.\.?$/
+ File.delete(base_directory + '/' + file)
+ end
+ Dir.delete(base_directory)
+ end
+end
\ No newline at end of file
diff --git a/app/models/photo_tag.rb b/app/models/photo_tag.rb
new file mode 100644
index 0000000..37d4235
--- /dev/null
+++ b/app/models/photo_tag.rb
@@ -0,0 +1,5 @@
+class PhotoTag < ActiveRecord::Base
+ belongs_to :photo
+ belongs_to :tag
+ validates_presence_of :photo_id, :tag_id, :x, :y
+end
\ No newline at end of file
diff --git a/app/models/tag.rb b/app/models/tag.rb
new file mode 100644
index 0000000..f26ae2c
--- /dev/null
+++ b/app/models/tag.rb
@@ -0,0 +1,28 @@
+class Tag < ActiveRecord::Base
+ validates_format_of :name, :with => /^\w+$/
+ validates_uniqueness_of :name
+
+ has_and_belongs_to_many :pages, :order => 'pages.name ASC'
+ has_and_belongs_to_many :albums, :order => 'albums.name ASC'
+
+ has_many :photo_tags, :dependent => :destroy
+ has_many :photos, :through => :photo_tags
+
+ def self.popular_tags
+ tags = Page.popular_tags
+ a_tags = Album.popular_tags
+ p_tags = Photo.popular_tags
+
+ [ a_tags, p_tags ].each do |ary|
+ ary.each do |tag|
+ t = tags.detect { |t2| t2.name == tag.name }
+ if t
+ t.count = t.count.to_i + tag.count.to_i
+ else
+ tags << tag
+ end
+ end
+ end
+ tags.sort { |a,b| a.name <=> b.name }
+ end
+end
\ No newline at end of file
diff --git a/app/models/wiki_word.rb b/app/models/wiki_word.rb
new file mode 100644
index 0000000..59fb9dc
--- /dev/null
+++ b/app/models/wiki_word.rb
@@ -0,0 +1,2 @@
+class WikiWord < ActiveRecord::Base
+end
\ No newline at end of file
diff --git a/app/views/albums/_album_form.html.erb b/app/views/albums/_album_form.html.erb
new file mode 100644
index 0000000..be83507
--- /dev/null
+++ b/app/views/albums/_album_form.html.erb
@@ -0,0 +1,34 @@
+")
+ desc.gsub!("</pre></code>", "
+ <%= submit_button 'Update' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/albums/index.html.erb b/app/views/albums/index.html.erb new file mode 100644 index 0000000..27cc038 --- /dev/null +++ b/app/views/albums/index.html.erb @@ -0,0 +1,40 @@ +<% throw_content :for_sidebar do -%> + <% if allowed_to?(:create_albums) -%> Create An AlbumPopular Tags
+ <%= tag_cloud @tags %> +There were no albums found!
+<% else -%> +<%= album.name -%> (<%= album.photos.size -%> photos)
+ <% if album.album_thumbnail -%><% end -%> ++ <%= submit_button 'Create' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/albums/show.html.erb b/app/views/albums/show.html.erb new file mode 100644 index 0000000..56db457 --- /dev/null +++ b/app/views/albums/show.html.erb @@ -0,0 +1,30 @@ +<% throw_content :for_sidebar do -%> + <% if allowed_to?(:edit_album) -%> Edit Album<% end -%> + + <% if (idx + 1) % 3 == 0 or @album.photos.size == (idx + 1) -%>
<% end -%> +<% end -%> + +<% unless @album.tags.empty? -%> ++ <%= submit_button 'Update' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/authors/index.html.erb b/app/views/authors/index.html.erb new file mode 100644 index 0000000..da8862c --- /dev/null +++ b/app/views/authors/index.html.erb @@ -0,0 +1,14 @@ +<% throw_content :for_sidebar do -%> + <% if allowed_to?(:send_invitations) -%> Send InvitationThere were no authors found!
+<% else -%> ++ <%= submit_button 'Create' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/authors/show.html.erb b/app/views/authors/show.html.erb new file mode 100644 index 0000000..3a2b56b --- /dev/null +++ b/app/views/authors/show.html.erb @@ -0,0 +1,8 @@ +<% throw_content :for_sidebar do -%> + <% if @author.id == session[:author_id] or allowed_to?(:edit_author, @author) -%> Edit Author+ <%= submit_button 'Create' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/exceptions/internal_server_error.html.erb b/app/views/exceptions/internal_server_error.html.erb new file mode 100644 index 0000000..aadbfad --- /dev/null +++ b/app/views/exceptions/internal_server_error.html.erb @@ -0,0 +1,216 @@ + + + ++ | ++ <%= (line.match(/^([^:]+)/)[1] rescue 'unknown').sub(/\/((opt|usr)\/local\/lib\/(ruby\/)?(gems\/)?(1.8\/)?(gems\/)?|.+\/app\/)/, '') %> + <% unless line.match(/\.erb:/) %> + in "<%= line.match(/:in `(.+)'$/)[1] rescue '?' %>" + <% else %> + (ERB Template) + <% end %> + | ++ <%=lineno%> + | +
+ | +<% (__caller_lines__(file, lineno, 5) rescue []).each do |llineno, lcode, lcurrent| %> +<%= llineno %><%='' if llineno==lineno.to_i %><%= lcode.size > 90 ? CGI.escapeHTML(lcode[0..90])+'......' : CGI.escapeHTML(lcode) %><%='' if llineno==lineno.to_i %> +<% end %> + + | +
<%= params[:exception] %>
diff --git a/app/views/exceptions/not_found.html.erb b/app/views/exceptions/not_found.html.erb new file mode 100644 index 0000000..036107a --- /dev/null +++ b/app/views/exceptions/not_found.html.erb @@ -0,0 +1 @@ +The requested resource <%= h(request.uri) -%> could not be found.
diff --git a/app/views/invitations/_invitation.text.erb b/app/views/invitations/_invitation.text.erb new file mode 100644 index 0000000..7c58ca3 --- /dev/null +++ b/app/views/invitations/_invitation.text.erb @@ -0,0 +1,11 @@ +Hello, + +You have been given an invitation to join the TuxBliki. +Check it out at: http://penguincoder.org + +Sign up for your account with this address: + <%= url(:new_author, :invitation_code => @invitation.code) %> + +Thanks, + +The PenguinCoding Initiative diff --git a/app/views/invitations/new.html.erb b/app/views/invitations/new.html.erb new file mode 100644 index 0000000..24bb1b7 --- /dev/null +++ b/app/views/invitations/new.html.erb @@ -0,0 +1,11 @@ +<% form_for :invitation, :action => url(:invitation) do -%> + ++ <%= submit_button 'Send' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/layout/application.html.erb b/app/views/layout/application.html.erb new file mode 100644 index 0000000..ef6b033 --- /dev/null +++ b/app/views/layout/application.html.erb @@ -0,0 +1,88 @@ + + + + +Popular Tags
+ <%= tag_cloud @tags %> +There are no news posts, yet.
+ +<% else -%> + + <% @news.each do |page| -%> + <%= partial 'pages/page', :with => [ page ] %> + <% end -%> + + <% if @page_count > 0 -%> +<%= submit_button 'Update' %>
+<% end -%> + + diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb new file mode 100644 index 0000000..c9204a7 --- /dev/null +++ b/app/views/pages/index.html.erb @@ -0,0 +1,16 @@ +<% throw_content :for_sidebar do -%> +Popular Tags
+ <%= tag_cloud @tags %> +No pages were found!
+<% else -%> +<%= submit_button 'Create' %>
+<% end -%> + + \ No newline at end of file diff --git a/app/views/pages/show.html.erb b/app/views/pages/show.html.erb new file mode 100644 index 0000000..c84dc58 --- /dev/null +++ b/app/views/pages/show.html.erb @@ -0,0 +1,9 @@ +<% throw_content :for_sidebar do -%> + <% if allowed_to?(:edit_page, @page) -%> Edit page+ <%= submit_button 'Save' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/permissions/show.html.erb b/app/views/permissions/show.html.erb new file mode 100644 index 0000000..4bb3f69 --- /dev/null +++ b/app/views/permissions/show.html.erb @@ -0,0 +1,14 @@ +<% throw_content :for_sidebar do -%> + <%= @author.name -%>User has no permissions.
+<% else -%> ++ <% if @photo.nil? or @photo.photo_tags.empty? -%> + None. + <% else -%> + <%= @photo.photo_tags.collect { |t| + str = "#{t.tag.name}" + if @editable + str += " ( Remove)" + end + str += "" }.join(', ') %> + <% end -%> +
diff --git a/app/views/photos/edit.html.erb b/app/views/photos/edit.html.erb new file mode 100644 index 0000000..44e479a --- /dev/null +++ b/app/views/photos/edit.html.erb @@ -0,0 +1,17 @@ +<% throw_content :for_sidebar do -%> + Back to <%= @photo.album.name -%>+ <%= submit_button 'Update' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/photos/new.html.erb b/app/views/photos/new.html.erb new file mode 100644 index 0000000..fcd5724 --- /dev/null +++ b/app/views/photos/new.html.erb @@ -0,0 +1,17 @@ +<% throw_content :for_sidebar do -%> + <% if @photo.album -%> Back to <%= @photo.album.name -%>+ <%= submit_button 'Create' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/photos/show.html.erb b/app/views/photos/show.html.erb new file mode 100644 index 0000000..a6a8dea --- /dev/null +++ b/app/views/photos/show.html.erb @@ -0,0 +1,231 @@ +<% throw_content :for_stylesheet do -%> +#photo_block { + z-index: 0; + border: 1px solid black; + padding: 0px; + width: <%= @width -%>px; + height: <%= @height -%>px; + background-image: url('/photos/screen/<%= @photo.id -%>'); + background-repeat: no-repeat; +} +#photo_block_container { + margin: 10px <%= (600 - @width) / 2 -%>px 20px <%= (600 - @width) / 2 -%>px; +} +#photo_tag_box { + position: relative; + z-index: 2; + width: 100px; + height: 100px; + border: 7px solid #6f9bdc; + left: 0; + top: 0; + display: none; +} +#inner_photo_tag_box { + border: 2px solid black; + width: 96px; + height: 96px; +} +#photo_tag_editor { + margin-bottom: 10px; +} +<% end -%> + +<% throw_content :for_javascript do -%> + +function show_tag_at(x, y) +{ + $('photo_tag_box').style.top = (y - 50) + 'px'; + $('photo_tag_box').style.left = (x - 50) + 'px'; + $('photo_tag_box').style.display = 'block'; +} + +function hide_tag_box() +{ + $('photo_tag_box').style.display = 'none'; +} + +function set_coordinates(x, y) +{ + $('cartesian_x').innerHTML = x; + $('cartesian_y').innerHTML = y; + $('photo_tag[x]').value = x; + $('photo_tag[y]').value = y; + show_tag_at(x, y); +} + +var block_box = true; +function set_coordinates_from_event(event) +{ + if(block_box) + return; + var xcoord = (event.offsetX ? event.offsetX : (event.pageX - $('photo_block').offsetLeft)); + var ycoord = (event.offsetY ? event.offsetY : (event.pageY - $('photo_block').offsetTop)); + if(xcoord < 0) + xcoord = 0; + if(xcoord > <%= @width -%>) + xcoord = <%= @width -%>; + if(ycoord < 0) + ycoord = 0; + if(ycoord > <%= @height -%>) + ycoord = <%= @height -%>; + set_coordinates(xcoord, ycoord); +} + +function update_tag_selection(tag_name) +{ + var new_tag = tag_name.innerHTML.gsub(/\<[^>]+\>/, ''); + var existing_tags = $('tags').value.gsub(/( |^)[^ ]+$/, ''); + var plus_space = (existing_tags.length == 0 ? '' : ' '); + $('tags').value = existing_tags + plus_space + new_tag; + $('tags').focus(); +} + +function photo_tag_effect() +{ + new Effect.Highlight('photo_tags', {duration: 2.0}); +} + +function save_new_tags() +{ + $('save').disabled = true; + $('indicator').show(); + + new Ajax.Updater( + { success: 'photo_tags', failure: 'photo_tag_errors' }, + '<%= url(:photo_tag) -%>', + { + parameters: Form.serialize($('photo_tag_fields')), + asynchronous: false, + onSuccess: function() { + set_coordinates(0, 0); + hide_tag_box(); + $('tags').value = ''; + photo_tag_effect(); + } + } + ); + + $('indicator').hide(); + $('save').disabled = false; +} + +function destroy_photo_tag(tag_id) +{ + $('indicator').show(); + new Ajax.Updater( + { success: 'photo_tags', failure: 'photo_tag_errors' }, + '/photo_tags/' + tag_id, + { + method: 'delete', + onSuccess: function() { + photo_tag_effect(); + }, + onComplete: function() { + $('indicator').hide(); + } + } + ); +} + +function toggle_photo_tag_editor(direction) +{ + if(direction) + { + // swap buttons + $('hide_photo_tag_editor').show(); + $('show_photo_tag_editor').hide(); + block_box = false; + + // update tags to editable mode + new Ajax.Updater( + 'photo_tags', + '/photo_tags/<%= @photo.id -%>?editable=true', + { + method: 'get', + onSuccess: function() { + photo_tag_effect(); + } + } + ); + + // transition in editor + new Effect.BlindDown('photo_tag_editor', {duration: 1.5}); + } + else + { + // toggle buttons + $('show_photo_tag_editor').show(); + $('hide_photo_tag_editor').hide(); + block_box = true; + + // transition out editable blocks + new Effect.BlindUp('photo_tag_editor', {duration: 1.5}); + + // update tags to read only + new Ajax.Updater( + 'photo_tags', + '/photo_tags/<%= @photo.id -%>', + { + method: 'get', + onSuccess: function() { + photo_tag_effect(); + } + } + ); + } +} + +<% end -%> + + + +<%= submit_button 'Login' -%>
+<% end -%> + + \ No newline at end of file diff --git a/app/views/tags/_tag_autocomplete_results.html.erb b/app/views/tags/_tag_autocomplete_results.html.erb new file mode 100644 index 0000000..c470b32 --- /dev/null +++ b/app/views/tags/_tag_autocomplete_results.html.erb @@ -0,0 +1,5 @@ ++ <%= submit_button 'Save' %> +
+<% end -%> \ No newline at end of file diff --git a/app/views/tags/index.html.erb b/app/views/tags/index.html.erb new file mode 100644 index 0000000..2eb5f7c --- /dev/null +++ b/app/views/tags/index.html.erb @@ -0,0 +1,8 @@ +<% if @tags.empty? -%> +No tags were found!
+<% else -%> +All Tags in TuxBliki
+ <%= tag_cloud @tags -%> +None!
+<% else -%> +None!
+<% else -%> +/, 'bq.' ], + [ /<\/blockquote>/, '' ], + [ /<\/?strike>/, '-' ], + [ /<\/?sup>/, '^' ], + [ /<\/?sub>/, '~' ], + [ /<\/?pre>/, '' ], + [ /<\/?code>/, '@' ], + [ /
/, "\n" ], + [ /<\/?[ou]l>/, '' ], + [ //, '* ' ], + [ /<\/li>/, '' ], + [ /\&\;/, '&' ] + ].each do |regexp| + node['body'].gsub!(regexp.first, regexp.last) + end + node['body'].gsub!(/ (.+)<\/a>/) do |match| + "\"#{\$2}\":#{\$1}" + end + p = Page.new :name => node['title'].gsub(/[^A-Za-z0-9 ]/, ''), :created_at => c, :description => node['body'], :published => true, :nid => node['nid'] + p.author_id = a.id + pages << p +end + +pages.each do |p| + p.save + if p.new_record? + \$stderr.puts "FAILED TO SAVE PAGE #{p.name} #{p.nid}" + p.errors.each_full { |msg| \$stderr.puts "* #{msg}" } + next + else + puts "Saved page #{p.id} for node #{p.nid}" + end + comments.data_seek(0) + comments.each_hash do |comment| + next unless comment['nid'].to_i == p.nid.to_i + c2 = Time.now + c2 -= (c2.to_i - comment['timestamp'].to_i).seconds + c = Comment.create(:comment => comment['comment'], :user => comment['name'], :url => comment['homepage'], :created_at => c2) + if c.new_record? + \$stderr.puts "FAILED TO SAVE COMMENT ON PAGE #{p.id} NODE #{p.nid}" + c.errors.each_full { |msg| \$stderr.puts "* #{msg}" } + else + puts "Saved comment id #{c.id} for page #{p.id} node #{p.nid}" + end + end +end.size + +EOF diff --git a/bin/import_zip.sh b/bin/import_zip.sh new file mode 100755 index 0000000..dc3035d --- /dev/null +++ b/bin/import_zip.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +if [[ $# -ne 3 ]] ; then + echo Usage: $0 [zipfile] [author_name] [album_name] + exit 1 +fi + +merb -i < album.id, + :file => { + :content_type => 'image/jpeg', + :size => ifile.size, + :tempfile => ifile, + :filename => ifile_name + } + photo.author_id = author.id + unless photo.save + \$stderr.puts "PHOTO (#{ifile_name}) SAVE FAILED:" + photo.errors.each_full { |msg| \$stderr.puts " * #{msg}" } + end + end +end + +EOF diff --git a/config/database.yml.template b/config/database.yml.template new file mode 100644 index 0000000..b8aa471 --- /dev/null +++ b/config/database.yml.template @@ -0,0 +1,16 @@ +--- +# This is a sample database file for the DataMapper ORM +:development: &defaults + :adapter: mysql + :username: andrew + :password: + :socket: /var/lib/mysql/mysql.sock + :database: tuxbliki_development + +:test: + <<: *defaults + :database: tuxbliki_test + +:production: + <<: *defaults + :database: tuxbliki_production diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..01db9a0 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,6 @@ +Merb.logger.info("Loaded DEVELOPMENT Environment...") +Merb::Config.use { |c| + c[:exception_details] = true + c[:reload_classes] = true + c[:reload_time] = 0.5 +} \ No newline at end of file diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e6d99e6 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,5 @@ +Merb.logger.info("Loaded PRODUCTION Environment...") +Merb::Config.use { |c| + c[:exception_details] = false + c[:reload_classes] = false +} \ No newline at end of file diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..0ea51d1 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,6 @@ +Merb.logger.info("Loaded TEST Environment...") +Merb::Config.use { |c| + c[:exception_details] = true + c[:reload_classes] = true + c[:reload_time] = 0.5 +} \ No newline at end of file diff --git a/config/init.rb b/config/init.rb new file mode 100644 index 0000000..9e376b2 --- /dev/null +++ b/config/init.rb @@ -0,0 +1,27 @@ +Gem.clear_paths +Gem.path.unshift(Merb.root / "gems") +$LOAD_PATH.unshift(Merb.root / "lib") + +Merb::Config.use do |c| + c[:session_secret_key] = '9e6d92dd24c39be48946fc947255476fa4d7f7e9' + c[:session_store] = :activerecord +end + +use_orm :activerecord +use_test :rspec + +dependencies 'merb_helpers', 'merb_has_flash', 'merb-mailer' +require 'redcloth' +require 'RMagick' +require 'memcache' +require 'memcache_util' + +Merb::BootLoader.after_app_loads do + config_path = File.join(Merb.root, 'config', 'memcache.yml') + if File.file?(config_path) and File.readable?(config_path) + memcache_connection_str = YAML.load(File.read(config_path)) + else + memcache_connection_str = 'localhost:11211' + end + CACHE = MemCache.new memcache_connection_str +end diff --git a/config/memcache.yml.template b/config/memcache.yml.template new file mode 100644 index 0000000..fc6a95d --- /dev/null +++ b/config/memcache.yml.template @@ -0,0 +1 @@ +localhost:11211 diff --git a/config/rack.rb b/config/rack.rb new file mode 100644 index 0000000..f00cf55 --- /dev/null +++ b/config/rack.rb @@ -0,0 +1 @@ +run Merb::Rack::Application.new \ No newline at end of file diff --git a/config/router.rb b/config/router.rb new file mode 100644 index 0000000..49b50a4 --- /dev/null +++ b/config/router.rb @@ -0,0 +1,34 @@ +Merb.logger.info("Compiling routes...") +Merb::Router.prepare do |r| + r.match('/node/:id').to( + :controller => 'node', + :action => 'show' + ) + r.resources :pages + r.resources :comments + r.resources :tags + r.match('/tags/auto_complete').to( + :controller => 'tags', + :action => 'auto_complete' + ) + r.resources :authors + r.resources :sessions + r.resources :permissions + r.resources :news + r.resources :invitations + r.resources :albums + r.resources :photos + r.match('/photos/thumbnail/:id').to( + :controller => 'photos', + :action => 'thumbnail' + ) + r.match('/photos/screen/:id').to( + :controller => 'photos', + :action => 'screen' + ) + r.resources :photo_tags + r.match('/').to( + :controller => 'news', + :action => 'index' + ) +end diff --git a/public/images/accessories-text-editor.png b/public/images/accessories-text-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..188e1c12bd2de0029c75eefc6c7c4753b86b7d9b GIT binary patch literal 574 zcmV-E0>S->P) 2^qNERY3;<4Z cwkNNp7Zp5;AjKf{B7T6H z7K$;wTN)8fToCQSV$+QqO#Q&sZ0iseT9M6oFhjF#YAe3W{|(Ih&u?blgZ~U+lHy(Z zfEnP}R(g1dys47_mq#z10cH*!ci4`$5?D>W0r2hlIkux$PfFdaJ1vdV-c&$Y6 qM6=z7>zUrb8|$BG>39|jmV1jOTU#EGRpi+xRHO?}@de@`-W?HM1Qj5D_ogg}SY zdLN|}^?H57O9w%Kn@Oz|d&_(+O?3c05d+({v28n2?E5}$CdJ@bk;TUuUX_ ^(h)oH!))dmc3|x7NH+_f7=kKWb2fXhZ zrnAjAMhLXlWV2a*$wSOL4(~qIS$aJMy=iu>tN_|Hp>9hMh9SE@rg`+GoBO#O-SQ {L5?nn?G7$uQNU|ANHWktGp13@enLu*Z~ zRzquzloG8qLI{Kqt=k(B1Emy><7_&0#$ rONYp%AR;3TFv378LqNi9NDLwpLI@#*5JHd;@f`eP6#p2{&y$n$e9!Z} zZ{%f#G*IOPoWLFcM@L5hfP;gBva&LbMzgiGH99)Fu&_{9S4X}tDJdBl8IedN2?+_C zo10BdP37g~J3BiNLN1rv)z#J5*jQa%y}P@+zrWwo(lR+YDVNLXbb4lH=F-yA`uci* zf4`TPS3p33LZO(Oo3mIf!NI{wrBWu7MMXtTO-+rBjisihc6WDgY;5G`=eM`F_w@Ai z_4Q?BWTd5~Wo2cl)#~Nt<)WgZ!^6Xdh6WakB@_yilapyQT3lS*#KeSDDosgA;cz(H z+uQT=^EEX!D=RB&Yil7PAtsXvMNuA)*U`~YP*4yZ9qs4mmzS3}Gcz+dIOy)~URYQd z78aJ2lw@yjZ)a!M+1a_ex*8J`v$wZrHk)&Da&mKX7Z(?eMx(Q{vzwb6+2sFy_(u-P zh@`~u(6|VRkJ$PZ^6&iLIpGC2RJU(r^FF fDPY(_+xK*Ua--+ z1j~XYn2-3WPJD@{`*s)zPzyu_aAXvWO-|2XEXzxh{-c(~X6SzT{ssKiA{d_?J&}Jb zPikNqEwDxq7a(x<(lQ{;zzhjR+#@gsn|16Yl^GP82JQK RD$9h@H*3{0Oa{~;xh6KW_B6k`kwMS oRZuRA5>5k-jlT|@G5?*N96lg!>$$6TRlN!s;i!wnUmrF5dS;8SWsGr>Oe#N zmqtA^&QYDtOUD#v5k4E2Cki=O8ZzWb^&l%{V(f4vSmHY*a?QBzfM1E10MU@NjT)H$ z#wLYyb&y&D@&xo|Pm_-FXvDph31)CAlpCw6!~>eSOfnCASOrvRSAEY|H@m (X&m>F|rNFyW4G^C-aFw&SAky|6SCM&nJRO)Ek#X230xiIJ=v1_}I zsdka< ~uL@RWoWcxrHR8>3n~`KjVC!*ZX g~`F01i+vpc)z;2EYLd z22{f%BLFx+!GLOHbQAywC>T(Uj*S7}00jf8v3KtPaDajV)w}U=034uTKs7!w0e}M( z45%h1CjoGPf&ta!`}Y7iK*50O{nQiy4p1 ho00$@-P<@!52EYLd22|4@KLX$Y z1p}&&Gcy1 o-sU_dqh`7;0x zP%xnSY_R~~00jdo%a< i_q=5a6I+K;SG0ER)S*waZXw3?&SwK_JjpRzfdb zmJBI(a3SFYT$!vCi4sIQ8fD#RD!C@1xADTwpO!ncfA=IAiMA%jtroNkI^ wHL@SB(1l^z#5FUvSF|gt*p8&zb18+eBh*HK4>Jd0<*>uqw!5NcA$*w zx=U$8=Lj@LLFaQEX=syL@F-Y?vuB$t%eMGn+w9neO3gHP0AICo_lrZbsPx+lxVw9p zP9iMf^r|EsB~S5|$XuP-B6DrRl3KR!HcF7$h0mE@8SU*zw3VqbWq0zZlcI1?zyF^` z?%JF&(tW=4 CmwY2#5>hAI{| 2`}+}> 5?1jffC^L+A1Ho~JuK zPJjQ 56eR%;2;xWc95wY@x#%z1&p`go_r%y(c{Q41f#IyHg3R|8g zk6mlgHq5=f;8zo0cd6nbS7BS9&q0&V50s%vfo4G+`A^hM5vgm4o2k3)%daQ@2fy2^ zsbjz>y4*9ZLpKJ^k9U#uW123~y4P8INdt4TF%mzwbT4_b FJCQ>mJA%&{%K$d!9C +^3Eb?2L==iB7>IS!J@x5^Nwp9;8 z-Gis7p i_Rh`V}vd8kQA-xz6{rAG^>-Sikqu*$A3 z!Ut;~s~l?`meeeo9ctL j3wia`w*LqdEp%Vd8y4+bzAH BTp<4U`|d zSfOAJXu<<<$4NOd5pzgT6yP39%9eb?G$XA2d2~{?TH$Qw7Wws5lV0>M^%+J)^KW&K za{LCJPyJAo-TMCYTct {?$OWmSPrBwn$%dY9Wjyed(exX78ezab&zw6BL1wV zi2u5SoM#rf%=}!$pF&pSme;sU8w^2qJo16Zzq+{hS+6_v;5<93cEf@`NoA|ug}ktx z8 ~?nSbbuES69GR zZocaDKsaAb+4^_g=CiF|3DqC!GeU+J)Ar#+OgU8*CU&J9Q;QuJQ`O0OSIRzht9R$6 zoadg2gv+?~{gszgTz$f$cwC6PoO(#-ndb3HDrToPR_)O5Sb1^loxIimK5VRa6FyUi z@=&y+SxPs@yXy6RC|bSBa>;FJhdS)~G__2vcUwfYc`DRixv&G{?tb}MC^wbXGCJ!1 z ~4Q#28w>`w%* Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00OK@L_t(I%Z-vtZxd$}hM#XdnVTCEU&1(18>Ug9t`t~g(IrAvH(dc$ z+g-M#S@kclg@3>wKr~V-)JR>mfgRnTSS?X0BvmFM$<)D~IAhNwp84iu;YQ+C!Mi(0 zub%TBog;XQT=(=Bw(b04+jilk*X?%uS(aXGwf395ORnpt4}O23Ue@yR&ynl8gV(+K z|1iY8dn;^jZw)I2zpeaQ1hV%6NGS_TOFu9@J&k3VIF7@^hpR#eG4ck$^So=CrrnZK zG8haHnm{iUsMja>>Bqa`#Q4p(U#rbcpL)Hngb oi?+d zUBt01(j*}W0{-1^^Stwzq~Bw8b(Kq(J|C`-W-0xC52fI*$7`JNKE^vYOFwM0v9`nU zU;w!y%_X&3jqR;%+U<~|BpCv7nIokHK+`m=;wk=q^arLf!k>@UXa#$m8Y|Oie8Q6_ zPx n7IfN9zM zv+2_c0*n!zZnw+A!U9uMQ{+;D%*Zl{Gg|sDfqE5STNYWCahxQWhQZ?EB6D+d%+Jp= zK0Z#dSVRaxnhrpzR}*NOAdZKzEX%_8eVWZChlhuhN+l*ICn=AO4c}B~Bu5ES=7mDJ zT)sX!I*RMom1&q%D;3d;V~qr4-F(lQ0Z9f8jh)FQQhhg38md-O=JWekMH6yQb^< ztt`tjfFKCsbF&vpx`57p3(K;oR4Rnw0a9k9X^K)x3L#RZ)c4}`-=3M7`4l({e5q;L qWd#!g_VPSm25tlE>+9<~C;k_v??1QHVkU6_0000 Jed}|-^E>z4Yp9T&OuxanN3r9* zrs~v5#G6scEjUz8JyvYgga>b#s U`QrO0c#1IjBdV1*Y?%o|m1Xaa#U4T8o)0t7;6{=WyK2NB)L*Ce=qaEn8 z5r(ckWNB#$RRusq= s>kl&-TwhzOqN;ro6$MQv?uP|$bz0attPv$2^i3u?kqEXzh!i9{l( zYWW_FF+qWdVB0ozhmP%kM5 zx3Gm4xdpMBJoD-$_%7_Xvomw%oHOrtFx`Lr ^WEf$Nal4djU=`)|tiB;;q z`>TJAntwh2<6)9ZA!Sb@GLyM1WGSmoy2)K0@|0KChACVTid0m$rYT(+%2YN}m8o16 zs)Tj}H#Ar@Q(Zl$kDG;AnpKY_ayJk2G_PhsGTb68(xRFawds~&nU)1dTCLnFtkR09 zum%j$u!I&l27?VWSTt7)>X;Mm>0Ygmu|yFb=}|2g79=w~)3Z BbH?AsB_Q1`N`4LJJ-Y1{>(=6?HXfVotF!j6@$}iE>=B_I2#LlVgQ#^Vmw) z4x`)k;a#^5J9-I2VIvLFy_3PCfd@3#fh}R)(4^acE-i^y;X&W$ekZiDujQ4Edk<&d z-&|h3vitto&&j*xTi4&-nEcX*YuhJh-=1&nX>;fG)ydbp(~ozKzU z>(+hgZbB+K2 literal 0 HcmV?d00001 diff --git a/public/images/document-save.png b/public/images/document-save.png new file mode 100644 index 0000000000000000000000000000000000000000..22ff49571020a2b520d34f622673bea031cbbf2d GIT binary patch literal 911 zcmV;A191F_P) UFWod3@ax5SUXmoUNIxjD3X>Dy`V=irVb7^B}VQg$JV|oe-V{&C- zbY)~9cWHEJAarPDAV*0}P%H{)baZe!FE4j@cP?jXZE!Aca%X3X$43AF0)$CKK~y-) zosvyRRACf`pSj)f=Fj9z;I%Q$k+M;2QBgD|6u8J1MHDVVC@g}Csliq)D#}F>R1gMI zv?vN9uqY^MThJnjM2e r z*tjzZQ~_IohM*?d(88ZT78%aXyXViH;2#P!cXaKIt*nn#mz#sDYsxyRBZX^i&nNvY z!|UGX>ciJj;*mGYx;yU-{}qrteZJeB8awQX#;6}=+9+dz9;B^hBg-ombNT)Y{GmQ# z1>=94?<9FFC0|AcL_}oZb6R@S1CqM-L=p!tNYAS;()IMMw4S;y?*@nEcUhJtsg9)R zhVHYpJjTSt1mTi$w7?{V;sDV1aTK#e=lghu_XD3;vZxRO075}Q0RXz^f+)dPitQ(E z%-gYda01u!x!CiPi#;y^czkvr$ZTH&P@+)2qU%s20PVYX(wJDs%#2Mmq|uaE&)(MU z0PJaAf$|k1G6xV5B9Sl^Wic)tSjWw~4~WOA& h Fy#?;glwrvv%h2{W;VNh9FnHS!gh7CNsvH<|wws9PX>FMctA?pDB z{r$MEo7eC>4_()D?>`lZMDjE6Jdbob&B(|InM?)|K}0YNgQ1}zLZMKuT9$=nS@~B` zN>N-~L@*f4eG&lIbrCfS6E%B2<@@;-!r?HbrKLopQ2?^pEI=;pcwHQ&6!E$`lu|5- lMst<}sgC3s;57fI&R>%|GfdSYVr>8b002ovPDHLkV1jlggmVA@ literal 0 HcmV?d00001 diff --git a/public/images/edit-clear.png b/public/images/edit-clear.png new file mode 100644 index 0000000000000000000000000000000000000000..e6c8e8b9f341cbf3a1795631ccaafd14b0e0c911 GIT binary patch literal 773 zcmV+g1N!`lP) 5 zl1pfmXB38?@0*$EOcI;hNJ5iHyw#`_D<+Ey(t?XhOLl^ng^SURf+GA21zi{y1{{!5 z5QL7#g ;8=>?7hOBWP~@Qv%4i?;^z?o7$2sh!G| zts6JQ<4rGsx`hNvL;&d8r%uFIa{QCF&sB3vJ3Xhnz3G3(a_m%-#>gcR&L l0E*wJ36qI~C2ft2! !GOpKDtrJ2lSaNQ|Hgjn@93PsJ(gZ`2+IBy96 z0wag|dVeYUtj2Xcip4zE2Iz1NmGK?q-I(0Ec_nX5@MXf0%df=eg{JcD1;K)00000NkvXXu0mjf Dmc(vD literal 0 HcmV?d00001 diff --git a/public/images/edit-delete.png b/public/images/edit-delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ea03150a1c15ec650240042fb695e7be84bc3e28 GIT binary patch literal 680 zcmV;Z0$2TsP)
&~9SKOY%f 0nX^lS0%q#YP1;Cv`C~wifvVWH7q5i>VkBIIeP6 z?s|6)au-91QGBQO`{sE*@B4fS?A7A^!aG@(#_<=$akkoxxl9xQXmcpb()eup8Wcsb zgoa^snGM6hljX9thz?EX=K SV+MNuFK0-`7)n@QnL;d#!A@UhW?AP8tQ8h?ynYKO=6BACOv97OzXrAtf@ z2O)x1X8|H-V>nD%fY=%S{{Wx9i2r094LW{B44uo@Kw#`p>kX`0Uo?09s&V;JTzyn7 zDU*{^%-Y&}CK{d4s?`b^i%n^@T9ulJ#`L$9H{{~N1F9 )O#I0o&NqHSeDc6cDqz8 zK1}bwAaOHui(g)OtONMGwY4emZr<;5I_X`d&8)9~I0*nN&z?HdsoA#LQO@rNluJuR z`2EL^Bopb;WFp zK~y-)os&CgR6!JmzjMwkxtp6^18RJrXd*$e2&7R2QLq&&i9r-ZB}mX15fqbR1q)m8 zfe%CwE48uE&MJ*!W3!coML-dg-E}uhbl1H*V{wz%M2MMYnBt%LKF&YFD%QR|yQY8x zkRYoFf8T%ba8EwpO?|F}{_h2%+7rh)ip3(o8h&L2dj~fM(Fh2*OvJa@pEvsYb`%B% z29crRqd`P*&M;>l593xs8lM5NUHGS$~9D#XJeNU zQy!l?kErtU>IABabAd;9h9@81J~mmHI8wMcdWfxCHnDNTdSv+cP%tx`Im|hn8Ri^j zM!8(3R;}Ud@45Tn9v|MlW@mo~{k;ulzr5n@RD!Ass*0MRrid!4im9S1hzfC(&}y}q zt4)(}P1?yk)%k4zIPU`@9^Y0(Jc{7Gr!9i_f#3sO*@R3+QCmkV=^%;%-SITQ$_M~j ziO07~WL%R*<1c}V7^;S-p`w_jK~+UXQG~VmCWPfj>=pxyFRG*jswoYUcI}@EDY7ku zY)L_EfxuW)2+Jy%C{IQ&prYJAGlHpd>%=Kkl&53k2#OEZj-puNxQlwd$*0dowyQU- z_SuosOFeK4^Ea2CXJ%)pl&fry-}v$C&-F*?tM820NYt5^q@AZ!Dy{4 Qps literal 0 HcmV?d00001 diff --git a/public/images/emblem-readonly.png b/public/images/emblem-readonly.png new file mode 100644 index 0000000000000000000000000000000000000000..04666196e552e14afa664f56bd2312c66bbb199c GIT binary patch literal 430 zcmV;f0a5;mP) z4jvs+H&M;MdVlo~3xi*=OJ?_woqWD+!X0r)Eth>zf6~#I~h_x=;wA-Dd z+**KQozrf0=yrP`uv~tU=PNp$9=PN9&m5``MT8K_&{aPpgh0?h*3ZgnLD8Uy3TAf5 zKt#}>1StVDDuN)wzMjU2m?2ivf~uktc>kCKFrUwkT3ak;+}}L_LQ1IyAm|C&2XH%X zK}ArJQ pKIZ YZ=>v}zGvq^U;qFB07*qoM6N<$f<&0NlmGw# literal 0 HcmV?d00001 diff --git a/public/images/emblem-unreadable.png b/public/images/emblem-unreadable.png new file mode 100644 index 0000000000000000000000000000000000000000..93edaf03f849940a306db4ff75bb6abc3bb33667 GIT binary patch literal 518 zcmV+h0{Q)kP) dnSF-Q}QlMiV*ii zyO#IQtCM20Ysk8Z)#%Ph=ezfwE1B7R`T_XL9?M$$k=cBzeb;P0RllJvm&^akJ|2$& zXaOpUdM`^TOQ nD?0KqxTW&>%uV+v`8{0b!r zk5^YHP3v(2j~5r1g9FTH1R CfaNgyGK zI#hE262r5zZUyfq6PQdo<~42uY&M%Vere*(=P#f3`p&@3AEt*DvUi(Ro&W#<07*qo IM6N<$f?S%`;{X5v literal 0 HcmV?d00001 diff --git a/public/images/face-monkey.png b/public/images/face-monkey.png new file mode 100644 index 0000000000000000000000000000000000000000..69db8fa5b5e06ac699018e5c702ca91c8c532018 GIT binary patch literal 784 zcmV+r1MmEaP) L zli!O}br{A!@AsUUvvcN*PRoj2bd{Sd&NeBNKgtoI$b@CrRd8V!1(&)>D!MAN#r}YZ z2&9X;sBZE?K^>w+DXC>41BYZ+*I7!CwJsuQnVoZX&+MG@eZ5h!jDmVDUmiX@ygZMn zD*s3BUk^i-;9$n^l0tuKS?>t9jWC~B&ROKcTD@f-^vk^jLzRN-h<@T4M#?>_e$lh! zGsJo k4)?gtUXM#yru#4H0qn5AH1$ z*5pqBn07m^RLi{p_{B#7%kcOF!{ZZZXNBP-$Jlq|7-<~hukAq _4_|4`p$PxJ>I?cnLVR2H#f_{ z!51m`KAI+In$T=EIX!ui{!*E#3#WAMmu9mW+1*o(aK L7t^BLREQobBQf|8?Z|| @EY}#5i93I-kp@HX! zqKL2+;(IQ+j0-j;o9W`#!cB}YfA(@q@AtqepMEv{V|1f&1;_6})!>QJ-R06HASO$8 zT`xcXG{-lWuSKeS_D~b|Rf3};^4{L+HgCuFs?+_*IpR+b|c|M;Eh@2BjA=}RjL zZ`SJJM-Kt+*0~RK)WCLyeueb{zX@Em@B_%nTD{fy+b#T8nSZzZv+e+GZy^;e&C$XD O0000 0)+jEP) K`lbtXsaQ;_vX7l#~~rDr9s7q55D1?^Pcy->cq+1jZ7wU zlQn3qYkyT=9D4NlK21=UuUwMzXD_T<^nH(qLk}pI%cq|`ef}hzKdJx=2+Z^gX$a(w z9jEZI&}<1~ =5GIr#kTnFBp0JiPWk?d?LkQ*GNyW<-J8)xZA^$>*C zq1Y(iRq@ )?S0J5PtwTX&lprAhpJoaZL@8vfr+s?gTEz;V*Ee=RvcJHi~u5nQVJ14 z1Y!}QNC=`B9SYSjB8Y@!qIE^U^ISG1t1MPDUl% wcY$LzW`je V_=-2-nyCN)002ovPDHLkV1icx6Sn{W literal 0 HcmV?d00001 diff --git a/public/images/go-first.png b/public/images/go-first.png new file mode 100644 index 0000000000000000000000000000000000000000..9c15c09e95c3430b5bd1bf24e7a01e8203a2e9a8 GIT binary patch literal 666 zcmV;L0%iS)P) hqp0JED290h! zVU0NBR?cr`p~-QQ_EsWfBH@EQ`Nc0GKMZR^J`BSAxf26@WBs>$$pHKvI7xf7HPn_K z?i~+>+atsnZ|Jg4VBK;@ =p(qz`$(+u}xd3d6n3+*N?MDJ7VE8(JO(EzhB^&{0eRn zE*?mNaRLBn_0NHlrd}YI5_3+{j?R9X$}BA9ySqF4x2)2Bd@j8KF~Xg@H(lYH;N~^f z^&poLB>)3X(jI*{c`tpTvp3}I9wGn`t_kK+f;Jb)x5~Mcm=MA{nSJ@R@P7JTO$g5q z)>vRYlF^9H&d+2YJejC8!ZrPk8zPM`j$uE{Us}u$`^<2oGynhq07*qoM6N<$f}(68 A0{{R3 literal 0 HcmV?d00001 diff --git a/public/images/go-home.png b/public/images/go-home.png new file mode 100644 index 0000000000000000000000000000000000000000..a46fb2220648f4640d48fc34273682db5fc53415 GIT binary patch literal 606 zcmV-k0-^nhP) zpi=LK3kbe)ph6$1us|E@0bs(3;j70N?ldxwS=dZZ43B3h07Tynj^2Yc@GQ zog*HPBZLSEeBTewh7gSA^VD1y1GodMPMto({n9-)s&51E$;vZU9zR8k5p<`8Fh N|A1evk_=AdpfbrNok-0q9`y@lykUZ{9CDA`)68V_>uX4$tQ( z0GBRKb2S=6>TxbhlkH7H6&U>${F{F7rSIMjqS-ib^#eg962Z1@5{U!?i4YKr#c&*F s0J1DA{1>jzI OV literal 0 HcmV?d00001 diff --git a/public/images/go-last.png b/public/images/go-last.png new file mode 100644 index 0000000000000000000000000000000000000000..6e904efd06236206721c6a662ec8ecfe74e971c5 GIT binary patch literal 685 zcmV;e0#f~nP) 5 zlTApJQ51%s``vp#$I+r-vIvbVC s0U1TC~hLW^i)Pz0@_MiE-%s!hV+qFhuE z1Zm_VBKtFl7NgQ1VznuPg3$S4O4HHl`{uj1g=uPI)C+fW&f$UkzUK&QElXA3suR|5 zJ<;J``J?$u(U`UXPO+vn)Kyk&?u@qR+tHXVUk qlzip{BLi%w!$yRaxEd1FmzWb`T3ks8r@G#>8hztmaZq7PV0 zbE3nanxCyZt880y97jl`qmV)&9f_2Z=U?uj9L4I=^=w>K!{FN|e&4{&F>6dCFan?e zj0t%B{u)}App{FB8^U#6l+*|z$>u-tJ)Ndz>rP!+QC-#j=7+F8kYqg7L`aMj4y< zNHX_ G5`zmT}-uUontb9=r!a)e|uV|)6#W_-^(UF 2DL6`zGMn!p-|9fRGGizh?e=&U5++$Mxhv T)(+xx00000NkvXXu0mjfgrPr^ literal 0 HcmV?d00001 diff --git a/public/images/go-next.png b/public/images/go-next.png new file mode 100644 index 0000000000000000000000000000000000000000..6ef8de76e0f5bf01c09da24a07c61cfe558d7a4b GIT binary patch literal 676 zcmV;V0$crwP) 5 zl1oTbVI0MO-{a21M#B_R#9l-oXcPp6(?)2~B7y{4Mu9@O$#RS~LMu0okc%jC6BNCq zMPfd15iMrWDWnuP(IPA}ow0!)<9P4f`?UyPGZWN-v-$pq!}*{8hcSkHhP!mEu~WAd zo8?nd1jeIrclCk3aF;a@j#!~$nl%(P0Jzf98$5aR>}dqE;fU4n-v&x*nhu}wwKrd{ z4f;b9;fU2%OeY#6`YVQ=TOJkJo9%;vsn26nmF>ePxAA!V*2;(ZnPFo%AB#FaHw-$p z>A83xDHKX5gpddX0EtgSc(|1Lcd)Cxp7`{*Gd4M}fH9|HQD+7~1Grv}*vDrmsZm0K z5C{Q60m5V1o+G_9&%wGQR!!BO+NWc8C&Ce{BNlb~H9*c=C7oHocC*-S7Ns<$C1sQZ zLijB|M!48sj(1C=)P(9pYjao0(5pv%$FEw)G{Dl2Io>B nm(2P=eF~WywGEfv2*dEE+1BNH1p0gO_(!va6Ym6#!ZeU0XL$ zmOyFA$XqYlC#eqYr*8WRCf~&E#M}5+ `DMhod1o}n6nu_w#4?v#yZPlMNv2Zf#pvLQ?bsc$8%}?|wxEMGI60fdRAO~{ zc52bv6uF?Yza^+BugrY=o*FhT7dA)!rvyS0Urwj)#iE6g^YI%&-U+mBcICDJ0000< KMNUMnLSTZVNH5j^ literal 0 HcmV?d00001 diff --git a/public/images/go-previous.png b/public/images/go-previous.png new file mode 100644 index 0000000000000000000000000000000000000000..659cd90d7f80488a8a6a2c12f6f9e5ad98720461 GIT binary patch literal 655 zcmV;A0&x9_P) _fWZPlDqB9?#%D^>oA$FjP8SXdVl!5?|TnYO4RbBH?=GA zTUy2|reO< ?=@r%h} zW6#cJQfPC~s>mwxzQ}>D!BbZalds_8_h}r7_JCAa@f4F))r6lUrCf(hQ;9=;jU5L& z+1FnmP_XjQREAhnABYqX00}@!0U-tMq%XJx@e~^h8rvWApSa|&uWz9Di?6_?1E%N@ zl4EB68Hfl3f`qGnd$iXb;n;2VsHt)P`R?O`My|Agci-NCF&}hI2Ui3vQGjU{P_$N1 zwo6b*g`Wk{x;wF^0p~U>`wvX#H%c-OZ~=##s0b5Wa!4-09SO%4;Ep?Tu9$V#I5TQr z&Mtkq{`h6ugzb~9dlQg)8A30C1pt3Qg&t7B3bbY+H`>YWThbX9oF#2!=nK7F-=6arTX3U &+XWy2~<%(BYwFX|c pI#R>7P%^)q3wROKeC1m2{1 ;d)-SojU@w(jc%E56*P2;2#k#9_@jK^~zJ>61yZcC=M0 s?F$Zz$K -YS={|^`_I7nD%2vGn4JBd<4X8-^I literal 0 HcmV?d00001 diff --git a/public/images/header_shadow.gif b/public/images/header_shadow.gif new file mode 100644 index 0000000000000000000000000000000000000000..9de7956bdb519a2992f5268d232ea6bafb2f6411 GIT binary patch literal 87 zcmZ?wbh9u|lw{yyIK;}Zef#!Hmo7bf_U!A|umAr2`ws&;3_t)n<^0M7t*KyZHC1w??>xEt=fabLR*P`s^00F8@s%vX0ly3W2Q;1iYQ`2d{1 zn56SU!aH>A*UV&krU`gE?uNYufcfLL`>KjUEiXOnoQe)`qCG}W|1bb+O7eK1#?QvJ zs|dgU_0&(D106tZ+zosBJd?&v>q nWFmUKydqeslSKE)YIWlRZ)Gjda>n*%4R*)(?6s}$J0tF zrB0rXshXW1sfM?{P>GRo72Li*T~yy3kh%V?FTe2QhE1d6Y3 FzU6LKF3;uj?|T^;O;NgH2_-9*%2UxlCj?MeRpHZ4w8sFjOr1-Y$4FjHVOs`O z6+Qs2{*%TqbaEVv&fkX!tu7E!h&mkz2FsQcy_m!>B&KO#Sq7GA5DFBqd&fqUQXD+m zfn!?;p^>;U$?D=fJf(uyMMMY XO4>Md`aVN{(Y9gut;(G&D3o z09{?N%Y*_27>1l 9_a8%EHtR(M(E9O_Gnox*SF!%CmFQBU zOF`};huu%zOT%N; EOv}x2@;w%)hg>aX0MU5~e$Dv-j=Valc(v;nT_sm!fGJ@x&;<^^bV( zeDYmpd~&)e>v=ba>Hp#^rKnR%1p%a#U9+> W8+D$+wD1(hb7ZnxQ)>0#;WVhSMx1M~WOW`<`(y-`~O?lW3>LcLKl zTI-Q&y-_m`fH8kDju%^KPiHOVtHdSC#>A0E7_i?tf 4s(+R0|vB7qwa4%ryoayflfE%+4_t0F6nNx)`Z6qVHi=FPKTS#CU}=K zz{+W!#C9YIhrSlXiNSHls7#+^Yo;a`d;);QTNPSAe+|gJYq?(Q!^i)DrRoA3o7+RD wat;teu)4CGrROk3N|^!cjmHn~jryI>0JT`*mWx6Xs{jB107*qoM6N<$f&tz34gdfE literal 0 HcmV?d00001 diff --git a/public/images/internet-group-chat.png b/public/images/internet-group-chat.png new file mode 100644 index 0000000000000000000000000000000000000000..f6e83254b638a2b939e71f07b182dae793009080 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE
9PK^lLGYXua=0dqb|0 z(0Aed#4mEkrXFFQVIkRU)!iwO@P)-K`H`TB-dCnMEei~^#gkV`ducIu)E`>3<^AjG zztK&BfkHBj6^DMzTFe^of29Ve$ooUjD*2X*ObOZ>y?Y%u!-GJf7{-VfofVRNRrl^& zA4u7ByT`KOXwIvCK3V<4ybKHqr#Hn33O05;u<$d!$H2qsdoZIxGtYU;WIu=L8{Rt1 zcMa9-|9(@J`Qv$g`5*Dqb~CuG?wq}|YY~H>BZuJ)ub;a966xg(BCQv{ZcM%SH|N!2 z9dFH+1n23Q)!EOlecrSASW_MIFQcQU1?I~ieR%rw>)mljBv$9#p2l!3b5 8*Q7;IDui+ui&r$;~AC~$Nu>2&ag&oQMh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00QhuL_t(I%dL}LXj^3*hoASH_nc#sG-;dWqm6CW(4s83b+X9Bt0|~3 z6mOI%-9=?M5O0K`ptn*G#rs`|6-PnD>5WW=H?uIcvzCo^E3WHYKeL=HA5C(SbCR6b z3)#f&*5~^FdoKR`eu4)${@&~<;4NLs{R%AQ`wgX7&~)wW+|1M$58jLW!S}zMG rL#P4P+<|J^kR=q!LjUR<=1mzj7BLp1miL0MTgZr{|x^iYGDyl!|! #OL6OV`f;PXlOge)!c#$#{SGXl@)s^XbSCXaYk@OhXc|B#CG* zL-81~z96~mqojuij=b@~*=YbR90{B}oE@c7E^@~W5Fg%$Qs65 I} literal 0 HcmV?d00001 diff --git a/public/images/mail-message-new.png b/public/images/mail-message-new.png new file mode 100644 index 0000000000000000000000000000000000000000..7c68cb8d35d52dd168e8e236fcec3a3f8942c2b1 GIT binary patch literal 619 zcmV-x0+juUP) x~Vjlni0r*Ko zK~y-)t&>e?6Hyd}zey&^WXPmVQ`0OWh3ZNaOEGCg5G|%+ih>mde-K@XNWqN=?gepU z5em|cx~cn8LG8-6__Ii2P>g6PSZu1`B4f&%Op?jC5Tip9Q1tHJdFLG7z4tu$$CCb( zXqVkl@b5#C`>|~SW=7H~&*XOG8#k{H0=b`Ox2w+lVxGOpY}V%sM4?;-F>jaoCU+8F zy>jgrXyu?*L>TcQTTTm!k5y`SQ&7#woy6}8c}luYrDB5hl7apLvCVNTX_xA U7sXzby1-Ub)&hq5(9Lvie7#$rW z)YF6CucE4Ps0S&2x`(^;imp(M*+(No$H(r!akLN)_acPJx$_rLRn;+@ucd8lR3|XS zI$eDUR#vBxG|P4vD2l@HaDs<(v+N%^0Duqz!!R%mgTmX_96oXs#jiCrEnC vXp#Z6asU|jc`xahV!Zb}30!`f28abPV zg{Pc2dAbQTtU4DjO|ZDMgkcB=y~QA#$#5v0rd~C%8x5>l6$y!k)nMn2?G)EPcWyz~ zbrQ)vKQ3gSgXjSiRin2rhOX;v4JPkQPhI|tk2uNysP7V2y6Y6gd4d1{002ovPDHLk FV1h5`60`sS literal 0 HcmV?d00001 diff --git a/public/images/penguincoder-logo.png b/public/images/penguincoder-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ac60a2555295c58f691b544f7fd8876b88e1d7 GIT binary patch literal 47493 zcmV*rKt#WZP) WFU8GbZ8({Xk{QrNlj4iWF>9@03ZNKL_t(|+MK<4ux8g) zFZNq&?{m&~zwgd{`}RDmrPgH0l5B)Ec#!?@0C{$ZnPL~u$pb&iNm1{QB#>040;KY) z9=tznLJ^8UK_~(NOdOXWU_jW#oXytJSSm&vW ^F+>d*|GE94 wt0;VW>upp#o5VXb2T0z>(6hscRQwaLg_I1BcakSQGGx8#_ zWYB;>0e~ZgD3PbJZc%ophDszM)ZTL$1>$2f@TITo9W!0+kQ5#=6p0i>Jv2sAAgc1} zdLLJpR^r@LuQSu_gz@=Z&;I$d-}?IcM*jkUs{j;00I&gI8o-Ku-)8sj2XGxgW50C( zjO_b%`~7bLj00E&aMSu^00#iv1K=EhTL5}!KT7~+0Ms_dEPx?^0>Ci<=K<_C_$C3I zw*Di4bpZPS>;Z7X`Wx8&M*zGH-~u*39>6;R5P%nLZWVx|0PeLpy=CyK!8vPlT(flm zfO)&u18@pJ*ZN!muoJ)$yFaoquGty^z?{LbZZL1RvDN^LS)0DKAKCnl*!OSS8o<^! zT{i&kG $kA6#_W6F+6-;K6W)-uB^xu?xP`6rn5_fb9xNM9cI^HkYdZii z1>mC1 V5r0c0l^m)z@#8mB_hP=h&U*bl7I^K zrRQQ4o4Tt~i-gco<_01lb^*>0V-zI>7L7duh=>9)vq)r$(Zv`=Rf@8#8eh5|8c~Ts zV~jkEO+n1e%v5y7)E7R~{WT|}zKaq)VyK8Hs)CsS?XMOZ!-zY*g1qkpX*9+Vn4NE= zQ(wKcLE9z@Kh-H*R2c&_MA1qmGAZI%;oZ*3@w#0%t((=w``+{5eP^G0{p7cnS5}VL zCaoC5+GZO!G6Y#L;@NGR#KuUr8{se6=00eMe;vRxMo@`>Rt(YaFeF+Au*(pA*4iyu ze|-RZt)D%1?d> _{+8q zGa0dVY& N>9<#a47=svQ z2ib k#j{9Rm2#fDu@y}#^6+`ktjhV0IKA?i$z&Bj-5c2RFpu7 z-Z>QB2@ysy)G^e<7(yM$`^I<2;d_&C)tD+VD>R4-L?uX+pu@g2Ym2_=uc=DI%oIdo z6QhLwP{PfXp)3y?5@Pm_8#d0)Of@q}uUny0c!&sw{lQod@v#p-@qP2m43iE{8p7VR zP3qa-Yqo)nA#cwZ3XG_h3<<}LIIh_DL_}8s9M6#c0)SVII2Wzmtc}|kF)i5`*Nn*L z4f&U?@9j2LZA8D4F(k@}H+?9RqL9H>XOcm%F<&+!Tmx{)2xZ+QjU~Ik$KY8vX1U#9 z=o>r(Yd^}yTeWpal2{_fB>B8;FiaRD-LU6I88cruLR!z(V$tAU%f?E~Y?ti|WsLf! zF(|cuE87=m*M7_OaLb;i&${hp&)T2P4!#{3BW|*_Uo@Oi+rK1n-?YD)9S%DT&S`rd znMD1%;fC6?llII_Yr9}$Ef|cuZNJEHdeY{$XwP*Ge-`a|Z?M+}$6U51J$wGV?cXAR zOK#`RJAN8O% d5x1fWtBk$^^2n3)?W5JJOH4HAPo<`EG& zA`a9}B1i}>HltES1VAhb9~?WVXbhotF$70Mk$u_tq6D#%7-K<@0H79?QdJltBux!f z5%xtR5`73GCs9I-py8+q&XIP?qGTX4ArMhe0vuCNRi_GoR3*mgZBvu|l|gfEab@L_ zAspGJEZK(lvQzz>A 4 z%KCZR?j>=4-o`y=2syC!M~#41GenQZ97=;ZXI>KqPg0|9T3^%l_fn=NtQoShG5J|r zvr~56*w{W}5OoH_z}C_mV_dd%PXw}RM9|o{%Na8qx93h8%$1E*n{+YC<{a#~>sfzE z;=E KV@w+iivad# z3`{e%`I^By%$V6&wnvk8V4Sx3&l-MS2XN5ZUbQ}!46dZ=2AlttOv+D(?xM|o+WNa} z>#@uBdo9y4Y5*g8@S%^spc!T<2(49%K&_#QDE+K}LZK=E6e RE%|% zoreP n9 z3vY~LDzN}CQjw8!?KmO=6`>GnNQ?>)m>ryR5D|)_frjA*G_+%&HRgdqQ0JgU33Uae zX#k1sd^}-pvf>?6W8xqX3D6Lr0L2(xkmww=R;YG5osInmkNo<+yYBhozx^No=O#l) z%_NkqQp?u+x4XXGGq?M2);^u4iBKd%_9Q8}Ozqq{t}~>HhN!Xy-g#q^Z*O5}v_-Yb zVN3APmhn276qUoT8EkYL>Ew1}(mw*j?Vgh@{nI~l-RU;_nBd>qCmSP}HD)Qdd6xbO zT=|cIKiRKF-{To?3~JgKYR{fsHwLm~*D+(Pl&SNYNv{7C?k2Tgj4|qMq;=i0cI0;N zx$Cn4QL74aYlm idGUs`j1*!0woc9Uyj9MYz*ENAR-V0oEV_l#zdl1 zl@==6{D^2NF?0bTCJqb=OdK7Pn)(Hi2+{~<2Vax`F=7m8LL`ZS(DKB{poSd N< (WRXC_9bQ3R01r#HwWx5`uUWvi%(H}J(kr=DW zQ_*r{jv^&Nxp1x~FsZ_YrY>V>_7!D${I$2wFARr6*&?DB8Sxfdh>J}X+HTi%X8cVm z3L68OH6)NNNRayK*-4)e`9P++l?Kah8*AOZ&)Bn){aZ04z8wQ vgQL8i_nv%qefLt^YMTPvTboZiNm&730nUuTlmHrqd+F-LFX zd_RDX0(cz2du;vhHT%{(?LewBhZ1GB#-nBvJeR>EHusRhnbv%t+1<)aJJ5`IH`!j2 zNsnExK&4OylnK-bv@nS(s>Di73{n+GL^TmXp-QT(prCMGi3;{Ua8VkP$cWSjf %xls*cAZ3ON5@SbI9TN}P@vy}Zg7@CR5rLe5NMa0V>Y8Gd zF~{meR8>?MV8^V)6bVoQfj}J Tf#V`b6?uhrEm>VLB#8qc)D0LGyin)o(cU;SzqpDM-5~>oSR0IsxmY4URdF$kV z{ovhqe*UZ9eD2kZ$d8y29A*bdwwH~}4s=h(5YC$Dom7+U+39w#d8W=~2H<2Iy=fBA zL#7hlG~?;IjkzoHN**+rZka*(P4oJ#W)jd?cCt2^*Y80S`&SM5f~hq JmXKNcWM%>Trbu*^IUN(E_jcosJ zTK^rJ?>1Y@LpJX D+T8cp*ypmtcwloJcf0o;`y3H@W*1ep%f#fI zYXJ2`V8^Z@A`xf>kx~h*Xv7>O#;y|Bl~v=4q9Epqm>2*l)T>AZkPv|+hA|L0DhlU| zh8QkNoKS!n1SV1@7rgT$KpiouXE!oF1XU%7R0@=&ASQ~c3L;@5tyrO>;joG^jF~h@ zA=Dl!6%j~P3qU;xK~+2vH!3ow(4z3gNF !)wOM`LhF%Gk)<_OP+ Y!i+B*rMx1OOn>SU{BlRU(8|k0m0&Gb2KybId5pvahPONEl uAZxSSb( zlOz!A6e `Bj-?V$R^)Fe&SnA@oe 0)GaFYI2KsdUcPXv)?r#Xk+RIJ3&uc_ot+$(TuHM4WqtCo&0d zyTRbIw#x>~8#boT929BZY5$8Y9@aj9PZ+Kx`_(8@|2mnI$7gEX$kuST?MdGl)4Va} zDLW7@8RHpcp&+kj&WXOYnJ`>fvo&AI4$K?}D|g_~13v{~5D~F2hK^W>0LQK-;zkJ$ zM9S *ZJ9X@8fC3S*b1o9G5V3;DR79=`6je PwJVS!jngWw5I|J{h;uGD=NeUEW{S?az(jS7F#yuA<62rLLQoZU z>_*P{2C7VihKU;{BF7AZMv1NDMb0z(q9LLN8kK;CKmrlf*eC&kK&%qW5Tgw1Fmw*F zQ@ZE~fuP#*Sx5-66Pi&^V>8agZ!8VN(zWY1f^Eo(om$>DbHSvOB_ps)hIk8xe3uL{ zQpm)m4AGXYtz<-X-jL@;78kW){Uh@%y=t(mWL~PSAy1vT;jb9c4!+Bm)Bcv`Gj3zO zY4ch$m>cVJ(WIcurb-m{?8%HFp3Wqa6kIxQ&&15uvtj+`hTz3a)l739n0x-JwU4&m z%l3UO>vLd4c_U*&H?k0w VHsy_j%#*6ylKxSk8lchz1t+FZl*3HQ_DhjScObYPN6G>F{l%UyU7!o z=DC&y2@edmPPSL8Hn-H?Wvcv|?SIGSav4BDkH7y@FSMwpF#j7=6%l}v1%E^Zf}o(* zfF2M*&cPQR&Uv){KZOX8gqfDv5JZLRCU{k}9KgJMtsP%MA_WnH*#$sVHF+n^(y5AM z6jv2!j1ZBw50TcuudSz(Tj&9eo0eyd)P^}A5V-9_0%D9{VmR+1s!V{S{)rhNKw?A; zP3r(KhXP_iY=)4~fDA4o202%t@E(dlgr;zcnXbp&u T+g(It=?AM zvi9HU#~nEGz`vo^&Bw$9ZF6 <0P0z^<|cCDXK zl}SM{Hf8IKgrk de!$xAFbQlb^Mtz0CU?Khv&rU|BX(oIPnhj%!sfEe;2hYzk{Wn_ z77TeLbJueQb52}inWwMJJd$Mw>t37FwCzoqdG*RHoaBKlZOCU5%U}zkmbO0IGPO7b z+m`mP3*g-*<+;qxlO&*j>Yyq!yzyoqdpJ|+z0Ieat%=JRu*+i5(z?}I%Gt&2z}TL} z#1+ @=UR8>sDAyfxEh=3m^@VdyD?BMAiVF}hyI>*~ zye~wZ3o5Z<$00P$RIB|_Bhok#ajaYugky{akv6K*5tX1yfmB+Dp^C)NIFph{B{HA| zzyt4Hzhxpy1o5K6v1xpOjuUZvLa1n~X1btl eLyRRmzz z5HU*x%E&snwHEuMCg}WR1&`=s6I>H95b#^wYV0@vk1sx519*StMREY1GdsYP*&Wu+ z@S6;~rMaeWX7P@Gdi^HrdIXJdEpENI RquS+2eH7T@KrH_gpMa@>8pV!DLiW|JLRaT$_P@gss%HvD3O8( zP2G%%LfN^Iwo&f{P#_=(D8>* 8G zP=1zsv;XUl|Er&R@ejWAbaH7=W;TyocAX-DSB#0(Mo2NUH;poc+iy%Gm~@eB9b*~s zteJRz)0o2RhERtAypWxsi Z}6}Y>kEeTvsp~p zDeM0p%fqXTAX8-gvccT5wMqGPVuZeuB_NM%z9|MOB{pBo;;6o9^Y3SWks04-P1TvV z^ Bk-@%T>o}PV%b7H`!{B?-=D}G+`^}7yU(Req z$8EhOlh_`%HHulp`Iyb;bvs~^+B{?Tb7?Z!(IS9VBHA`HGc(%1fB$-nu`?VFH?qCy zX42lZEUl=>aOeB%w`*CJ#<#PG``0tvUfz-oaLo30ul0S!9l7g~&nn>9`G$xDss$5q z;W!q=Ab_1iED9f;=R%cP;e^0KOd*O=h{D<$(czewnPaO8LfCNt;6&9ibJJ!{D@5BU z^$=sFpt`*eNUKJ%sxrV4&^9It5EXH)PDo8_?}8E#&FCc{6;joffvFIE$GfQ9GAxBk z1C?l2d@x9u5Q(6wD43{e86VU!M+O=|iJ-!5Dv~gBU}iNBq%%MwAdXd(fjWp3L6s-Q zs<30i>r{ttI`5uYZS)UMFRcI7tEbPO|I p0ZT+U}{VChcfeIrI?lEZoZW< zm6^;#$eH95vdR+4)3<8(Chgg!EGhYdA@sEMpL@7QnI|(D<;SyxVQ)m4jOZyP=Cbua zmF29l8E NrmCu%eBb-t*F66C I!tD}CuKS(wyA}St#{Bi!p zU;M>ApZUyZc7NzYADUcRT3R}N`gD;w2!^&c{mdXgn+3V%sX~bnU(W(_lgj^)wOh~T zlDyd|Gh)S)bK;2x1gI*j6W$ONQm_OFDGB+a5OS O= zB5*>;RI(%G$E6dk&X6THT%O8Q#j{2fO=iDI;Sy)J*bIWT8_R+wZ)TCo$OvI&i;YVS zsgnA3I?I8pGyBMTM%3xIS8Wd6%sw)f*+R-J`8dsM)d*vhCGN(Ic|~I^BZKvd%{QIi z=QHnBCyPDHldWGe7%ykcXP9}{)@-l3nI|pHzs#6>vU6=@*Zs`+ykXK>BKlj|UWJUn zSB&9YF=jW&B*^X-?`_C}V{<&~o9Z?)b(q>L7uxgjkAJ-X3%~FSkIc`{S0_%Kxbl&Y zeB}9+m6ZYj&CSix&;R_-zvIa#pPcjFJLjAnJ$lrA_OqXT@!4met+O%6_9?-*YHKty zDYwi#)s#uUE15@fEjw6J4(anYzvojZhbJP1Yncp@0z?tQ5K*WjDhdx~LKF}&Mdtv5 zY7-Sv1Ym*#io!crb*siPwVI)YBbfavv|c-bM1_b#VuVD|7 YsS8!S&G&bdv~ zKRH09bsmIJDZoq^LPgNjaIv8%LXk+Rbl5xD(U}gfl?9)koS6E3?oEH=H~*i%8Qv!S zBV 3lqIzG3NC&gv&xI@=%V+t9NqSn}!tj#% zawSWfX)?8<$|Nz}Qt?2t6BJo>2hF6t tbX#zC-1#@@nUaragpx5_ueBv{KG%|#&7@jZw~;- zJ@?#mVB5BBJKlWr&Ed1pK6`6sW~TdzPkdt6=RWtjy)VA_;>nGTjoeFEWO!6(4u^Of zPa BmGx8>SE$;3kUr5F=~6)}cTPV_pyDtugB>xcD? zK@&scqJW`71c|Cb5+jR 5oLI`m*8qJsuD8)ZbW!|eEHfxYg8Jv^Wf#-F)`3_OL=)dBk*&XbUA6Z z!P?eu${6#tENAj&R)J#O)b<-$fNP3bBYXCysg;L}X{K^8*RwRNf5?beGKP>dteMQd zcp|gMUBYHLn4}7J?D<)PEva(*d%a#~Y;0`uH-Gat&z?VjKK#-z{nDYCnVA&9K5ClA z4F-ey@BZ%Z&i%@-{K}P?nHj$8uDjlQ;J|_H`}Xa-e&WQ5m^plAZSSL9Ph^gwUY2?^ zW{h)J7EynBi(QVgME>vcih5=(G^i&ci7{3xk%*~wo(cuLfPzB7kd7!~h!Babt_6uz zRX8fDGBUx((3EW;1r6D`Aw*MVb&4V&5g8+*21HN^W1 *gS^L#&`DBxC}Ub{)@~J>l}o$Eyvoe0Rb)o}lr}So&0>OO=3z>R`Idb@ zWN`k??Ck8$4}9PQAAIn^2mjOU+qX|#x^(Hxv(G*|W(L~AnB$0u`tNzqdmi|qANrw3 zCnqOQzVXHzfAsm!e||Ds!+UJbciLE8oA=#WXvFr+6St6gS}z&FCFwJ%m ;rQi?~qmZ`+YGIeO5;Y2i#@g tFx+_HTdt+ii(E!p8OM*B7r} zzrOa&GtXREU0v0|U~uW$wQJb1V@IK?+cN1~GNwJ18TxM;4A%{psw}^79GewnbG$y9 zF}br_R7QB`e2gNV;bId;6_}*z6j7lZL?eTvcMefdkLoZc!Zi`ZyCOIWouVqE^FB%p zj+MwczX5iEi4^RDMccPFa1t<+vMYwF%0dmi^8 e{bxG8QMrmviYF3dDVyFv=kr?PJqQnr#SrN6Z{UvB4^A&AQ zWq@i$M8rfvpcMl_pbQDY*la^;x~E1^Xdtl-Hm#MU*BjGaGaZZ Tpt@%CZbU z_G3S` d$Lj$bcPTrVF50-MPT6sL=5~R>DNe7uMQsY$tX`S|YTvXm zgV{;Dw*RjgzAYO(7j15fB2rdWrPI^X5df}VyL$5wy?p6M{}rn71DO2tSFc<=e*E?Q zGcz-N0R4UY_LY0~?2(HXFRov^b}hlVZ2O%YMlOq$OSal2^DHOFMJlkkV&8Msan|q) zTTB)$(<+LhfrzU^D14_}S60u&g%Xbng~rf~wGmCl$T{DzQ)MP9J(pG0U5gS+RdK#3 z2O^PG)iWqUm7AuXEUU3aFe!<`F`(>gb}ZhpdWV_`)mW!;v(w{#W_lW(P6tzylU#b8 z@YK|UdQeAl6%>tXjE-5DD8MZ8 *hTuiC7(fJ~ks%U83?sx?2Z@fftpOo179?7S zrml!EAOMk2F}s=_H;CdzWsC^5s7@5j8x+GxB_Jx$D444X2WEQBww_xrm|vNgocg1; zZVg|3?fmt_wmB(BYiO#+J|m(Rj5(|tV|vSo>58>^+YoV=F^AJ8C3LnR>?m`I->^8O zOV<8?_5b%KL9Azz)7x1j@`fSX9oGL1Bj{QCe$9SAX;Mjz&4Pcyew)hzH@}I^0)hK% z+%s7y!zhI}JoVI5+dulzkAB}>cipwWCTi@11jqG0O7t z^1|}+^2N!?$-RdUAD##yOdLOc{09O2QHJEHe9qh0tdo8=b7G`*JcrHF(-CdC=#=A@ zV#g-%-IY5fv#C_JPot!QO-@d3`|yW9eEiClD~By41aK ({Pc zy;^_j$3MBfTz>7 uC}3m_(ulYU%d3IFL&;ou1D|h_K)22uBT3) zK6UMPfA{y!tgNg^7W h!4K)(Uc@lO^qODVopopSW2cZxnLsh-=QdVBQcdh&+O4_QTiq<|vZGAxD80s!L zKVafWQ0i8NpP3r(O!PW_`|NZzInndI?pU#Fep|I|cDlUp-n)x#w~L!M7xeh?H^YsE z1vz*2!f E!!qarG^xMYE(RjzdS`@`I+js8y%m4Df z`-O!&-|;ZA(|>Eaip%u%nam58f)IOI{+nj)^N8g5k3^%>miAkp#TNUB&tjVLRGQnR zPRts?tY=IworvSud|5-@7iR`x&c5T5pZp~M#83RhM~)sn`uU?rj~* lWCsrOnoB z{U=hN@RL9JljRTo;152vckkYxEz5G^>eZ`%{*|wM<@dkvg)b~-F8n5Q0CX}hBxPe! zRz4^NsV;08d)$7znI%W}w-~gO6C`G99<%=CHt9%rGxLxC*e5>nz^9&^pP0M$NBzlS zqf2cToKgvrF_4>ppn`@D!pU2{|H7FA^1FY0{?^4yp_Ab^8RPl$Ok&Mxf$`lh>xdaH z-VVRZ%)z8tXwbk16%rEXJlHvIn5iwVKtK>e5c2?vl#al?ZnaKU4Yd6)IwFeSy|W5c zDWRasadmLte7SROrn`6NeCLkC`^V _U GvvxEin@%jV#b`(X_t!ZO=XeUNkm`X zLMX}JaxNQBwlG@Byf&$ qQ%8UEG;d?5JDs(Ff&h0P4U#!R2yvvU~O$J*_Kk!Y%fbCskeCdkfp33 zBVufsW7kx*#-s&oS!c?eC<6e4kAM8*J7;HSfBNXrqfeD(=|n_S^&2*JlZ9TSxT^HR zj_X_U@;D2TC`?kmmEG5@#LGq&5PBwqt!K|A31=$vlJ2m+u4RX0szO0fX*yTFa=m;@ zJH5%!3pIQj*9egTxap(l_AyWfbBXd$C%B0_PY j_SAmFNo@QDxD7PfE&;3wmIWW z|0c3foGMEtTgjv=%2Je0XH07s0PmH=vD2<25-wZ_!{LMiXcTc&3&j|j$<BWne;GDzm-MeUJW`>R&IppuU>!^R^;Ridf zzy8MfH@^PO!C!sluh&*rR)z(UGLd6Kbc}(jdPmfc5_&4?sC6-lC<>4SC@EA6f;Iy2 zB2r2WwS>@NjT@xGq7>Jo7QOLq*frJBju#gdubsHI^v5SIFVy{Etx+W6x4xL%_j?Sf zlKrM{Oz2KCKwrx8;D*LDQs}`+Y*q`sW)aP6W?)WIz&(bT=}jgFvWV`(S=pKgY}|d= ztR;WePU@kl8uw Kr|!P{?)~HA;~oG8g8@#RIwdDho*X>)+;i*y@DKm6xVpN!0RYp})8T;! z9+>;s$38aw O9)oP%B2bQ>KEykTIXX%@|TLOgEXgF0cNO3gAuHoL@2Z zMY57KDOT!U0Jo;5re62nKfY_%uJ50op7w*mKyTf; aBonOCh{s>pD|aB{x% znCKPF!5gdC-f^gdpvwew3JgPpj|yT%z1YXtxn-axtR6gsol}HKW-P~uV0*l7IPg?v zBb+rxngXM*WNAFN45rt!Am*J};OrfCotX4#`~JAE#tMbHk%Uk x@+~iU5it#-=N(Ldp(kOUOW^l-P`g5CaoCW> nPW7ZOGqYITYsBotAl7r^3*sy@7Ha%0?wGDtjm zYY@Nm+{sJp!@5qMsQD~<`YJZx1DKcbNI8PZz F><0F*0IHCv$rFL9XBDIboM= z #%n%WrJ$p8O=}TW)`qG!a zbmjTypRb3*VX85n2wz`#;e}gAj~+ez?sva?TL=Nm%gZUEKEbhWhUV*b|I!xquFAY^ z@56V$s9`co8`){ssTknM2=F-@V~;)i;&1%MZ_wP_+{fnU=jWLj*REX~e)-E^Ui<1- zzk1N%TFBCSQdr3OERHEj5RaN;W)+*o8ewDIZMZOPxJH>%=6+*RA 2-mpD-)Y@KDVCq~z@Yf+q;2k~G-4dbWvC&tQOB?83TSL6Gj^Un3G&6+l8!Iz< z?J71zmMcKZ%= ?pSQyxd1up`dLGIo k9zXGpmOH z#3TUFC`SPa5k(?USvX%5g*fjNL4}Bf*)@(RkmDwX&=HAcYlYy@?+-?vx#{*g6^Nv6 z8ohe$8ZKSFBHw=LmHKPXezTsMn4ot)@W4bHal4HQ$G)kD^qmlERZ 2cLmwP_?d6x{Z~pQtH8iqkCQlATM9|3G z2B1k>Lq-dz6x d~Nn}wi8l}KxC(L#`#rDZ+$cUG2tPNf}ab@YHn@g+d zEg~u4^Fo%|5$%LbMgJ#lk&`5}l9hWIWvWzq?_Emi7+8OMvH5B&&5ZBK+p=M&RAZaJ z6PpF*(u-BoTYc`tX7$LJd2W&sf5`~_S_b1dHcLIHH>K>w=F1H(W`rHHxTYj+rXbmk zkA3W8)u%uG>7Rb^!3Xc%y?b|IuTew4-^cUMKY!~BU--hQ^XJdUEDC; O!WDrZ*4m%IZU GU?|^7B81- zgYACx)mQ1>d+(jEs)|$<3kwSyCr_TdS=aSUR+ZwW;mS^I7HdQn`Q6VBjPxd(lw_X5 z6|QCVv67c|XmBR8!fZCbeij6qiaRc5_?2FFwwR>BI?&wZ)m`JecC);)d}(xtLOO)9 zS3;tqztjisnnHa?fyn_TQ15!I-2JW}>3;D3X7sH~zr6DH+iwpudtGAwoJs7rvcTk2 zCVIcMy=2$v^=G?mos)MrReQaVNnq@~^Np}V$i+sWaOHp$u_`-#W+|Ox?|jj);|Rr& zn1e^rR~05AEsAo`8n!ixXg@ZQx|3r{>_#uV_V#s=Kd*^M-#GDBc>Rsza{1yVdhoux z$2K-LR79v#RjA6MEvIZ~)|Ou8NaVyj-*{h$iiUIN&WER;{_|%4zI{`>ckde8yLT_X z|FQR!-}?K%cdN@w1Yd-b(Z*E>6^<}!E1Ck#G*T5ukTsDA4UKcszIvw-h4>Ov Zu `AA#y5)cE*M3d+?%n%=2OoU!zCC;P_{GIV>GgW( zcDuZ?vJzi>@x|-cuU}uwY#SGiKoc`vYnn!$dFGk!+S=N4{eHju!V52KWR(amWN9tP zm{$H-F}Raz+{=>Ek)`q!nVoCGetSI&6G_GBrl+T;4|(tJ@ZLjJ^~Q}G%jeIZzhU#3 z$ihR0#y}UcN*O7gCKXgXn0XIxWc9R?`rbFmc#vf}q>7_S+CPy=kb~?%Ns@e$HN2j;% zKG1zfzd!ZHiBm6r{_~&TXqv`nDq(s{_6cLuZ`<1TvdSPy6InB(eM%Rb#O52QI~fBT z%L)Qq^!Ad|_NC0CVCQRsqVQgPTS6fa`w>9}j)b6q^Nqra^Eqlus{@E3qN++1Wq~F} zoH>7O?dGkOJ{11u^(%hq)~zx$jbC0_X|7zo7Vo<2PM(;UpaTc?yVccIN#;&=tj@bo z6h-vD2xVE-Wl=PaIc}`?>$7LhmZQ ?b+m8azC$s_`D@p%o&UL?`?=+{wY9M< )NKIUm}V-cI-G kAA<88#itY78e(j2d~M(5iVi#eSLYJ z=;e$7Ics+@3;NV7TtV^Og#a~^(y!Z`PG^C~>scz(_uA9cS6@}@;cyfl`u-1ZA8rg* zzV*d_*A&fSbUnCG!zuY@{GFfaJ^Yc+9oli=*i>0o9ssJUDt7JK6`gZU(=^MOq(x>{ zc-{7MV+$NGhIYGxh1YQVVui^Ax(;CEqlm8~v ^1!Tx2NP zbQ)C#DE9mPl2qZGYeI<9>6AW%5W=Wd@4XHNqe#$#h)TykcE=|*f@yVaJ%~ur?e?&3 z+cs=$^f%o)MC#ZnvlHi>6wXWG3vtXmGdU#(4({(1ML|GYT{MK?nx-BjNUWG6NNX;9 z!_0t0h(v1Yy3`N~Xskn!vH>f~ZgXJ!WSFXGqwsjXANkAQetY4$H{Lq4*F0lyW!dP* zGS#P-MSEYxcfXo^!&IpUGPNVU*mCyb#f$&)!3Q7w+1c6IS?Ao-J9qB _oS+ zc&gf-O%)5)Y;KpWO;W*9+R%wiJz2>RY|hlsTL3OqRW*6$%$avT@x&9KK6vopOuyfk zS6+GLt$x2>PESuCtm~T2oH-NDoH F7yw42Q9OP6^u?v6 zrNp#SIia^R 6@0j1Z+_pn)!b=~?&2JQnkzbgRNpMLsjy>a7)c<&cSqfs#& z4kuoH_0^5v{oUUUbzSFSA6tV|v85u&!^}KEM58F;fBawn+j}4T7oS*o;n}~szIyZA zXnOblYVVQzr;k1G?mbmiv07yoB0^CV)h9mjiGzRmhktnU`RAYCT77hn+1+ksDP>y^ ziGQqMq2A{EcVg!J#$YrVrH!j1;>H(+LPcW~#HQ{LQ`A^ HjqDZ$6-Ep_pxexd>k=GoIZV8mlkiasIW-XC`~sARX$>aK~Y0gi47<;E(UQ! zB@bWu>B;VBwpW(k$(7FB-V@jR@wI3E?i)M${r f0Y7%tU*8LbZU$wOloAu+9B;B)q=hxTQ)4D=cF>AEv57w ziGZ pZe6NPQUQN3)fXOmyXigflg-o^Uo L`JjT@5I~xgm(8-4cN)K{cv#PCMORglYhx zSz8~BLWo*b746--hi@$`#Lb$@l$D4O1~fP(*|BpwKJ)`m%^W*+%sJ<9?dny$^5VC{ z%JNcM?*>dzb)+)VsG?DU7zh$k2dM|}acXKpXL?Mtz3SwJg_RpeA9-TzlRxq4hnAO@ zzmJN}-~Yv5{KZ>M)68Z@z&T?SDd24vHeaJYpXuDQCY3E@-jFvRe)!@2b8~amkN)V7 z-u1>CZ@hbcety@)!~|~KxFO5S%jZX Q}$|C%^MMzq8Qq z_pcc-PGa*lUN^1(gBBC@O=IG_P3pU~MRi?Bc9x rz$qkcMAIyxwQ?>{HA8YR&T-SA_hS@rPLjb6$EfrUBkc+y9&y>h{7GMGvq2IIA$gfitD*3?!l}$rloIx``enPY5#X? zYwIVPnwpx%SH7nJ03ZNKL_t(FO~Zy^uuv%U(8R<96;Y|-A}@awNwzdxWmJ@1*B(+p zl#mz@k@NwiOIo_5ySux)q#HpxrD5pqE@_cw2m$Gm5|H{1?^>TfS?Ub;ea_xj?M(=2 zyuN? Dtj w|k zCYrq>8Jr$(JskWEu7=#+=PIDpF4B|mJM{~A-hJS4h{Z+}#?C_ydJ`kQb-c@hw;88Ul3`9JLjIbmST>jdJ8PzPL2 e_@R8 zJaV|in=oZO?d%vEnwz0aNz#ix0`gotFW;}W?__(E!t2Z@y#}GkK|M=bqbdGR5dkiU z3G?8;U%w2}omWXBL=ypo#KOZs(T4oxQGdSjh;tbZ`zlTSb@==J)mm3&ZZ3H#j4nDh zHeDi?qy^_?*gXiR5DTNxB}H<4_@F-Px-!-7?ow8y^G4F#PN6l(`?rD!*!2KUI>y)8 z$G9s@(ZfiTE*xxH^(tFr#%$24*atYYtfG}oXi1gQ-;(0rBnat){v8PKS1roo*b< zOUZ=#8m$VijEs!5X_T!@=Rv5WR2LV=So$Z~o>FzGQ;+s~zx#jJPv4FcH^O4eX)$GV zYjDl)_Na7tSZbxV+$=tnH!;c4akT@Y&<8yMyDsi0J32b_G?ROnF%?wtZ|@&OE7Y8q zv)+W|o=HH|kRXT80{W4#_ 9(T2j=CUAPgSz@t8&>TgH znsCg^aD6kK$VBxTwv8|m0(yw@%jmw7K%lj@+K3aj!PsJDXGcDs-1Se0Cd&k>Y0?liWzk;wlp3PwysH%djMSR!&oc5sq&%bH8?RyB$7y-fmn #`3tr^GvS7W1Qh!j3MJ$)|9M~dZl_BDrHsdQ#4=owb$pR5xf za~a5Bdzq>o0z`@m_acN)FC2VK@y6*jAy{qEDx8aL6fGnn@eEs7aNbozQ =?g!^CpSSe1e|u?oVHQakiJ0I%}E_7irvw-Bvq#dU_v+{h87ezw?YWl2Wy@i6526 zh_So}cu>eS=oquT=^WN`14b;1we+bO8Evj-0ITF&_y6bi&qu(#Mj0Z>GDx7~#Q9;s zzpgT`_4m(aVw| c z{rn+gJkNnEn#3#C7A|)`?B+W7b0gD=pP#?!sZ0F=iH;^tcJ{j_555OMiugaz5E1&h zcS==8o&srA{y?}|djw+Vtq@((2x5TiNypU&aPU4Z9$k7}sg%uPo!#6m0l4}2bAEnj z)-_AN%df-X=4|VAi_XN1t1f{1WZ~>yVmkBGDaUEX@{d#ymxlWK;H#6huH1%(* F}lq%GQ-#~~^1H$^v{JtlJ+)Y9V6HLTV4M^A~ z{=nFI9VXP0B8WCKSumnmOth0npkmOk#O6jyaV*~waR-SY=F!TinT{FGgNCj}SWxqD zwn1!RPUA#M)NsW}s|MonEhiFV%y>yWlprC@0Ko(*3p+dUj8M)Ic;oVW{)<0BBmXWB zq>PR8MI?Wpy!Ddsza)Ir$<9hc9fV?_B37H;zC4=x@8j{J- e6` zy~L@g@MQ?aeSTDk9+zLwX=5Knz5bhwCfhOS!9tt6{q(f_$NTF)fBqEB&8dm0s#e>+ z2G#sOH8r*UQ;)miG?~F%ay*?7vGd!tN56%WEC0@pj{8sG0=$61gmV>sfkUt*U8rPj zX=xcgw8<4ODf+=?p?dvdZ~6nnD2A(x%Qq9&MZCBnmO(C3G-OWc1oo4>SIiLR g;WP^-qz5`gV{OQxDU?o^!*%XCT!d{;4E+bFGG3@g~rCh?%J~Kma zS0XlN*I7~()P2P@1s4QV&_tvdBkG)0o$lD)qES6Og~xzM7Pqe zuE)U^=bc}%EVL5wZc)v}61x4`+e?QeI}}vMbweDRRx2z{_z7G){f(G0Rjup_(?9s5 z;b@NEq7_AnM8c7_qMhKJ_~@exjSOil(#*X@ro?&(hMeYjjw5IWR*KU2BR1$<%yOk; z+%y5*h=bG gm?;q}V9tC3tjD9REgi}cc3g<#nnDoH} z|6`Kl@kQxU#UhbS`n%JT^!pm$TmBrc x25%#2mzR+&8*|W2=O9nq?OzGJ<7qYf~ zzjt`(V_;y=%>$}kfi;1xRsm;nktG%=AwINeGMpCasLIO9e@{1ucKks_*2&1qs<>Z& z`>-wosHerZ{Ctr&Q0Q(FRjHMxn$WzfY_h2<$0T*L0uB3O;~RW~0AvS_Hv&GXC-A0| zRe+@g8B>hG^%6l89NBYeB`1z)EQMj9ktYtDq}#xcT``7RbQtN}KIt*0@P8IGxPApH z`!C?Hp=xPsqZ?z=C1G6q2v}HICGha@{Kdq=%E?MiZANQq*mzTGTwLO4h;w;?&^@kH zTEDn?dW|EjKu@r^SZB^{T&_KT`9-;049zi`#kJ7wE|xK#&3=9zcgYzoeS(DsvD%BD zRGt 6yw0z`~7e@`9QyMe)BMC!g{mU*x2|bkH*5(G^B8PZ-04Nr$~do7d!!; z*0we&ZEfu)80;!MQD09(V^^LER~C?Ts4+<${d?S~f$u+mCY%C$K>y$BRcBKz_%o>b z+x_D7Ro+9|t5-y^P2HRjG^_N`w$|1q+Cm=}mwLUb`6LZ`@l2vgELHE18>);ci-(8h zs--G2n#r!h;Z&owwWg!VMZiIs=iW((qAH8{_3Z_O^wryShkn)#ZkIc3635|k4eja5 z7p%V$x-7q{p};>oji8}m%&@Wx8l)$0iIq)MaBh(xA%0axP0Z+LeepIQ^Oa0@EhY+= zIohiX=jt@mVG`qr#pJO7%E6N0<{w%HIw7hd3TDKurSq IBbjA!Vij_*2fduC?4{`y#=@}W0 z;D!N!t~R>m =d+il|Yu2lCfS*ab*8DD$yGW8Q3=Qh} zMn$2XEL~^?mNH=W9TX6tkr&WJA}Nqg(ITt!e?J}n6mIPQW1y3%#chpsu-SR7(|6q) zppxO9o}QRf4;{1Up1V6fAm@qS^oBgo2i=Mtjr`IU-srjp$dGPOP|z8`Xm^E5dsFM{ z>uEp&Ed>?m7=(0B;MInG4)g?+g-Yn)OF!|A*S`0c^X3Eu1Qs27Si!=%H|E)%@BS@L z`ZabH7l#={E2^ujUjP`D3qEEByo_NS6rb%h^FRg$2LD>K@$^YoH#aZZLWlEh+4GrF z zyK6yWi${|#$p?_kQ-IC_=tonr5#det_V-U;UWuMy)JRrc7wHilf$J)Y DablP%*(xy}@$P5jR zjg7@(lIze5i- Li0(TW|s*wnm^qlSXKT2quz4bEtfb<7+P740FhBf&gDA>M38=z;^jA~ z1kt}IYij`7M6#t}K3-P&XWas$%}sNfeX~seeqZ +5Dp z!4FuFSqV~46IpwEdwDW!LC_Hnf8>g!bUs{G
wZ?kAZ+^yebW&NsYn{oorH2 H@PmGL5qG^1QV@6D8s+C>nC(FKpmyXyk9V34^g;Lo^z+8b-Hj$GKB{ z1#*^FR^DJCBc5+LrQH)$#^ygeS;&ivIyuIPg0FV^wq2cr0P$O!#o9s!+=y>VrTuYl zKW2M^YsJ{{cggx3BzZY^_|PDiPfyJFiK3j`Z+?8(WH>rH`T_oDoi?|lIR`Eopmob1 zt^nO~P?Aa*NF= ~djs6d>bAPN>DL$`Ki=L? zy&VAhS?(X;gEsWS?Yne;Wm>;@@#1qBQ2ai=c=_^S=lIypzC|Y#l>3yYn=Dc+pF 1GN*t?6JR?615@h=j-(t zDEI+_IR`LbqWx;Srmmh|GHCNYD=RB!pfdmbS1Rudd%$}9gY`by)RJ)ttNGf`a7vMH zYvcPOqf$8~aWhpn*9LLLzaP758v*naH?U6Td=dm!C P%^H=oSrH-vKn$o=!_g=d4fd%JO8=nJI|y&WKt0$2Xwb~M>^7U7$PX0k3_ zl1+Rkc^~s#bd8xK< xP{I=;u`2bU=r3evtdhqeG7*Mx0vFei~(0 zzQ ES5Ig?dQw%##CmOo}@g2Au-_r_;J!3hp5`dNU`?!nxjUNAN^6hR;-4#b 2uW0a%@xQ)7EEJI z0 PQ`aTH*ye?p{Jd;WgR8=jR zKLEX$CZ~;Kh)O1v3g?r!fhDpgwA$2B6z=VnB 2?~0>)gxqqLxTG& zQ=~>CxU`h^zM^TB_;Fa?&q;aS)%=tJvAY}wYgIM}LQ6JKSb#cx1cWZerwOb{Xc=*+ z;gkHwKu=%K`QgJeAT3GB%VP<+9cs+h(o1ZJ0 $-H#u 1l$u_os)La*s#n$Y8=}PwP3&D~o-nI>>S&*y z29ziY>qnqvadC04OI2V^9Uc5jKYoy1{{1`nl7#D9YYB>Ifur4s5CViRNqWmGSAiLD z9e$vHgUKKPVKkyySAKnZ0)|1TWI`~I`U7h;WJY(+<=!v1i|AV|s*ZL1f_byx2z7tx zx*0DzK0a #A|>Wc*iHQY%ww6v2rANG x4Akw&JtZC7{$IC78?yH{WbL_G?&3-TatxzCNKxPPI>4evolgdtG8)NQY z@>I+pKq1ZaqanGuxyJygk^(z+fr<=h)d*y}GckZ)(k1-@T_Pz(-|yz1byWwaYSnyJ zk!ZS7`lSco^N9`uB1zy?!RU{L 3bzx0NbOgzUd@7J1OY(leO*`HUB$kji!-(4{kK@CvEim6-8OR^PMldEp$j@X!O (>ALr` zaA3Mvev*{mi@gr$bSRQsQ^_h-^BoWfDG-UO4UrHbK3gM6OH=t0&wFoWH!?TDFS{yT zJpCSmeQ|qFMH=UgFQy1m{q+mJr7HV#7Z>%jKYo0xudgowp@A_qh#)9R-)o~WLJ+&$ zj DrKt91_s|u0T#z9*Q_hTF&+a~ z`qd>fxXH1y{LF(cAJ{aj>xbVU27>1I>D|}mldDYt5wwB%CSIdJQ(`nH|1|RgzF U#PTAMIVYsfUS)i67umMAPi>4n3xezkeJ5`#Nk562}d| z(4#YsejgbKIJa am#V6{Ds-nH z#WL3ZZ@;Y7R5PYhk{Jm?8|}Ca?EjMo5MFlEH#Vkhq<^kds&Ws`_Wy3LEIq+jY~e4` zh2 +4N)TAWPRf!UG62dsA`#+17Le=aJFbTF8o psH$El{`&3EaO`uEUxIDqoCNx> zaEP!_m(!N?QN(}Q8t1^3%OrS(B!D0ZE2Ehd{Z064NPs@Pev3D}=eS{xW`vmo0s%5P zGWTYtVg}hu&hk9mrqUSt=|703iAa)}$_6uo-2sXdpII^-CK#;X#O8R$!S6{vo2C`z z80c(~m0%?z-tYQsI(~y~7rUAR`zBgbU%k z^ulkTgjE_K?(~hnA&r~AYJ+?Ol6~sOyLGIcr sPQ`x zNyZ4_OD~!Q&Qz09sR=^2L+UtKJTqnSRHhby!>riubqVX`mgi!n2odf99h(Q@P&FR~ z>?g{2$$~Pys<63AUHA=nY#({~_ ^DU{I~xd zj73DS%u!HKVM1WGaBJYnQR~jPz+lb5Y2qM`ag$6C1s=vE=8EgQuI*<*2&l~314cLi zb1o8*TVlIDmzuxCD4emp{{|ZWdS+9^GXWjCBqPN7aH!Tc7!mNYG%*Q|s@6e(l&O{B zpWX18MmwsiJ`vR?{nZJuq_pv 7^KxfpfjsbDz4)R3=jUl*i9c1