Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter@walter-laptop.(none)>2009-01-15 16:58:52 (GMT)
committer Walter Bender <walter@walter-laptop.(none)>2009-01-15 16:58:52 (GMT)
commiteb4dfd4db9b8ae05ae95f3cfd72ee0bea4145a48 (patch)
tree0c535775e5d9c89e6187b7d1026c0b3c2ed2aef2
creating infoslicer project
-rw-r--r--GUI_Components/Compound_Widgets/Base_Widgets/Editable_Textbox.py294
-rw-r--r--GUI_Components/Compound_Widgets/Base_Widgets/Readonly_Textbox.py180
-rw-r--r--GUI_Components/Compound_Widgets/Base_Widgets/Textbox.py56
-rw-r--r--GUI_Components/Compound_Widgets/Base_Widgets/__init__.py0
-rw-r--r--GUI_Components/Compound_Widgets/Editing_View.py50
-rw-r--r--GUI_Components/Compound_Widgets/Gallery_View.py176
-rw-r--r--GUI_Components/Compound_Widgets/Library_View.py1141
-rw-r--r--GUI_Components/Compound_Widgets/Publish_View.py349
-rw-r--r--GUI_Components/Compound_Widgets/Reading_View.py74
-rw-r--r--GUI_Components/Compound_Widgets/__init__.py0
-rw-r--r--GUI_Components/Edit_Pane.py145
-rw-r--r--GUI_Components/Format_Pane.py98
-rw-r--r--GUI_Components/Image_Pane.py125
-rw-r--r--GUI_Components/Library_Pane.py106
-rw-r--r--GUI_Components/Pane.py32
-rw-r--r--GUI_Components/Publish_Pane.py42
-rw-r--r--GUI_Components/__init__.py21
-rw-r--r--INFO.txt21
-rw-r--r--Infoslicer_GUI.py435
-rw-r--r--LICENSE.txt339
-rw-r--r--Processing/Article/Article.py770
-rw-r--r--Processing/Article/Article_Data.py78
-rw-r--r--Processing/Article/Paragraph.py254
-rw-r--r--Processing/Article/Section.py324
-rw-r--r--Processing/Article/Sentence.py200
-rw-r--r--Processing/Article/__init__.py0
-rw-r--r--Processing/Article_Builder.py234
-rw-r--r--Processing/HTML_Parser.py256
-rw-r--r--Processing/IO_Manager.py552
-rw-r--r--Processing/MediaWiki_Helper.py263
-rw-r--r--Processing/MediaWiki_Parser.py79
-rw-r--r--Processing/NewtifulSoup.py9
-rw-r--r--Processing/Package_Creator.py229
-rw-r--r--Processing/__init__.py3
-rw-r--r--Processing/demolibrary/giraffe-blank.dita10
-rw-r--r--Processing/demolibrary/giraffe-wikipedia.dita968
-rw-r--r--Processing/demolibrary/images/120px-Siberian-Tiger.jpgbin0 -> 2716 bytes
-rw-r--r--Processing/demolibrary/images/120px-Siberischer_tiger_de_edit02.jpgbin0 -> 5396 bytes
-rw-r--r--Processing/demolibrary/images/120px-Tiger_cooling_off_at_Bandhavghar.jpgbin0 -> 2935 bytes
-rw-r--r--Processing/demolibrary/images/120px-Vibrissae_of_a_Tiger_at_Chester_Zoo.jpgbin0 -> 6282 bytes
-rw-r--r--Processing/demolibrary/images/140px-GD-EG-KomOmbo016.JPGbin0 -> 12468 bytes
-rw-r--r--Processing/demolibrary/images/140px-Jerusalem-coat-of-arms.svg.pngbin0 -> 32364 bytes
-rw-r--r--Processing/demolibrary/images/140px-Lion_pair2.jpgbin0 -> 8418 bytes
-rw-r--r--Processing/demolibrary/images/140px-P_l_Bleyenberghi.jpgbin0 -> 9114 bytes
-rw-r--r--Processing/demolibrary/images/150px-Climacoceras_gentryi_e.jpgbin0 -> 14754 bytes
-rw-r--r--Processing/demolibrary/images/150px-Giraffa_camelopardalis_angolensis_%28mating%29.jpgbin0 -> 9270 bytes
-rw-r--r--Processing/demolibrary/images/150px-Giraffes_IMG_9614.JPGbin0 -> 11013 bytes
-rw-r--r--Processing/demolibrary/images/150px-Kuniyoshi_Utagawa%2C_Tiger.jpgbin0 -> 35032 bytes
-rw-r--r--Processing/demolibrary/images/150px-Mare_and_foal_%28Kvetina-Marie%29.jpgbin0 -> 6194 bytes
-rw-r--r--Processing/demolibrary/images/150px-Tigergebiss.jpgbin0 -> 13777 bytes
-rw-r--r--Processing/demolibrary/images/150px-Zebra_eating.JPGbin0 -> 5973 bytes
-rw-r--r--Processing/demolibrary/images/150px-Zoo_UL%2C_Hartmann%27s_mountain_zebra.jpgbin0 -> 12316 bytes
-rw-r--r--Processing/demolibrary/images/180px-1990tiger.PNGbin0 -> 15920 bytes
-rw-r--r--Processing/demolibrary/images/180px-Asiatic.lioness.arp.jpgbin0 -> 8580 bytes
-rw-r--r--Processing/demolibrary/images/180px-Bertramliger.jpgbin0 -> 10326 bytes
-rw-r--r--Processing/demolibrary/images/180px-Circus_Lion_Tamer.jpgbin0 -> 9679 bytes
-rw-r--r--Processing/demolibrary/images/180px-Durer_lions_%28sketch%29.jpgbin0 -> 7853 bytes
-rw-r--r--Processing/demolibrary/images/180px-Female_Lion.JPGbin0 -> 9087 bytes
-rw-r--r--Processing/demolibrary/images/180px-Giraffe08_-_melbourne_zoo_edit.jpgbin0 -> 7115 bytes
-rw-r--r--Processing/demolibrary/images/180px-GiraffeSkelLyd2.pngbin0 -> 41856 bytes
-rw-r--r--Processing/demolibrary/images/180px-Giraffe_%28head%29.jpgbin0 -> 6702 bytes
-rw-r--r--Processing/demolibrary/images/180px-Giraffe_Ithala_KZN_South_Africa_Luca_Galuzzi_2004.JPGbin0 -> 8145 bytes
-rw-r--r--Processing/demolibrary/images/180px-HansomeLion_002.jpgbin0 -> 7778 bytes
-rw-r--r--Processing/demolibrary/images/180px-Lightmatter_lioness.jpgbin0 -> 9683 bytes
-rw-r--r--Processing/demolibrary/images/180px-Lion_-_melbourne_zoo.jpgbin0 -> 11576 bytes
-rw-r--r--Processing/demolibrary/images/180px-Lion_at_zoo.jpgbin0 -> 13475 bytes
-rw-r--r--Processing/demolibrary/images/180px-Lion_cub_with_mother.jpgbin0 -> 9084 bytes
-rw-r--r--Processing/demolibrary/images/180px-Lion_cubs_Serengeti.jpgbin0 -> 8619 bytes
-rw-r--r--Processing/demolibrary/images/180px-Male_Lion_and_Cub_Chitwa_South_Africa_Luca_Galuzzi_2004.JPGbin0 -> 9713 bytes
-rw-r--r--Processing/demolibrary/images/180px-Maneating_lion.jpgbin0 -> 9166 bytes
-rw-r--r--Processing/demolibrary/images/180px-Maneless_lion_from_Tsavo_East_National_Park.pngbin0 -> 45510 bytes
-rw-r--r--Processing/demolibrary/images/180px-Map_Guj_Nat_Parks_Sanctuary.pngbin0 -> 24668 bytes
-rw-r--r--Processing/demolibrary/images/180px-Matha.pngbin0 -> 107190 bytes
-rw-r--r--Processing/demolibrary/images/180px-Panthera_leo_Kruger_Skull.jpgbin0 -> 10395 bytes
-rw-r--r--Processing/demolibrary/images/180px-Panthera_tigris_amoyensis.jpgbin0 -> 7828 bytes
-rw-r--r--Processing/demolibrary/images/180px-Panthera_tigris_balica.jpgbin0 -> 10633 bytes
-rw-r--r--Processing/demolibrary/images/180px-Panthera_tigris_sondaica_01.jpgbin0 -> 10100 bytes
-rw-r--r--Processing/demolibrary/images/180px-Panthera_tigris_sumatran_subspecies.jpgbin0 -> 11173 bytes
-rw-r--r--Processing/demolibrary/images/180px-Panthera_tigris_virgata.jpgbin0 -> 22318 bytes
-rw-r--r--Processing/demolibrary/images/180px-PregnantLioness.jpgbin0 -> 8046 bytes
-rw-r--r--Processing/demolibrary/images/180px-Royal_Arms_of_Scotland.svg.pngbin0 -> 31474 bytes
-rw-r--r--Processing/demolibrary/images/180px-ShenDuGiraffePainting.jpgbin0 -> 12927 bytes
-rw-r--r--Processing/demolibrary/images/180px-Status_iucn2.3_CD.svg.pngbin0 -> 8685 bytes
-rw-r--r--Processing/demolibrary/images/180px-Status_iucn2.3_EN.svg.pngbin0 -> 8751 bytes
-rw-r--r--Processing/demolibrary/images/180px-Status_iucn3.1_VU.svg.pngbin0 -> 8562 bytes
-rw-r--r--Processing/demolibrary/images/180px-Tiger_032.jpgbin0 -> 15723 bytes
-rw-r--r--Processing/demolibrary/images/180px-Tiger_Bandavgarh_adjusted_levels.jpgbin0 -> 14816 bytes
-rw-r--r--Processing/demolibrary/images/180px-Tiger_in_the_snow_at_the_Detroit_Zoo_March_2008_pic_2.jpgbin0 -> 8754 bytes
-rw-r--r--Processing/demolibrary/images/180px-Tiger_in_the_water.jpgbin0 -> 13439 bytes
-rw-r--r--Processing/demolibrary/images/180px-Tigress-Jowlagiri.jpgbin0 -> 6858 bytes
-rw-r--r--Processing/demolibrary/images/180px-White_Lion.jpgbin0 -> 6500 bytes
-rw-r--r--Processing/demolibrary/images/180px-Zebra_Dallas_Zoo_1974.jpgbin0 -> 37733 bytes
-rw-r--r--Processing/demolibrary/images/200px-Lions_and_a_Zebra_a.jpgbin0 -> 9031 bytes
-rw-r--r--Processing/demolibrary/images/200px-Zebra-tame-jumping.jpgbin0 -> 5315 bytes
-rw-r--r--Processing/demolibrary/images/200px-Zebra2.jpgbin0 -> 13631 bytes
-rw-r--r--Processing/demolibrary/images/200px-Zebra_Botswana_edit02.jpgbin0 -> 14002 bytes
-rw-r--r--Processing/demolibrary/images/200px-Zebra_rownikowa_Equus_burchelli_boehmi_RB3.jpgbin0 -> 7418 bytes
-rw-r--r--Processing/demolibrary/images/220px-Tiger_distribution3.PNGbin0 -> 28994 bytes
-rw-r--r--Processing/demolibrary/images/225px-Una-lion.jpgbin0 -> 15544 bytes
-rw-r--r--Processing/demolibrary/images/230px-037tiger.jpgbin0 -> 11886 bytes
-rw-r--r--Processing/demolibrary/images/230px-Giraffa_camelopardalis_subspecies_map.jpgbin0 -> 14357 bytes
-rw-r--r--Processing/demolibrary/images/230px-Giraffe_standing.jpgbin0 -> 18388 bytes
-rw-r--r--Processing/demolibrary/images/230px-Golden_tiger_1_-_Buffalo_Zoo.jpgbin0 -> 16353 bytes
-rw-r--r--Processing/demolibrary/images/230px-Singapore_Zoo_Tigers.jpgbin0 -> 11127 bytes
-rw-r--r--Processing/demolibrary/images/230px-TigerSkelLyd1.pngbin0 -> 23666 bytes
-rw-r--r--Processing/demolibrary/images/240px-7_lions.jpgbin0 -> 13117 bytes
-rw-r--r--Processing/demolibrary/images/240px-ElephantbackTigerHunt.jpgbin0 -> 10060 bytes
-rw-r--r--Processing/demolibrary/images/240px-Flag_of_Sri_Lanka.svg.pngbin0 -> 8551 bytes
-rw-r--r--Processing/demolibrary/images/240px-Stud_327_with_Blesbuck.jpgbin0 -> 18582 bytes
-rw-r--r--Processing/demolibrary/images/240px-TigerSkinning.jpgbin0 -> 8650 bytes
-rw-r--r--Processing/demolibrary/images/250px-Beautiful_Zebra_in_South_Africa.JPGbin0 -> 24117 bytes
-rw-r--r--Processing/demolibrary/images/250px-Equus_grevyi_in_Kenya_%28male%29.jpgbin0 -> 16097 bytes
-rw-r--r--Processing/demolibrary/images/250px-LAzooZebra.jpgbin0 -> 15115 bytes
-rw-r--r--Processing/demolibrary/images/250px-Lion_distribution.svg.pngbin0 -> 32996 bytes
-rw-r--r--Processing/demolibrary/images/250px-Lion_in_Ngorongoro_Crater%2C_Tanzania.jpgbin0 -> 15097 bytes
-rw-r--r--Processing/demolibrary/images/250px-Lion_in_masai_mara.jpgbin0 -> 18589 bytes
-rw-r--r--Processing/demolibrary/images/250px-Lionesses%2C_Masai_Mara%2C_Kenya.jpgbin0 -> 17802 bytes
-rw-r--r--Processing/demolibrary/images/250px-Map_Guj_Nat_Parks_Sanctuary.pngbin0 -> 40220 bytes
-rw-r--r--Processing/demolibrary/images/250px-Mycenae_lion_gate_detail_dsc06384.jpgbin0 -> 16771 bytes
-rw-r--r--Processing/demolibrary/images/250px-Pride_of_lions.JPGbin0 -> 9912 bytes
-rw-r--r--Processing/demolibrary/images/250px-Serengeti_Lion_Running_saturated.jpgbin0 -> 7776 bytes
-rw-r--r--Processing/demolibrary/images/250px-Siberian_Tiger_sf.jpgbin0 -> 14336 bytes
-rw-r--r--Processing/demolibrary/images/250px-Tanzanian_Animals.jpgbin0 -> 9242 bytes
-rw-r--r--Processing/demolibrary/images/250px-Tiger_map.jpgbin0 -> 17287 bytes
-rw-r--r--Processing/demolibrary/images/250px-Tigerramki.jpgbin0 -> 15035 bytes
-rw-r--r--Processing/demolibrary/images/250px-Tipu_Sultan%27s_Tiger.JPGbin0 -> 7988 bytes
-rw-r--r--Processing/demolibrary/images/250px-WalterRothschildWithZebras.jpgbin0 -> 11164 bytes
-rw-r--r--Processing/demolibrary/images/250px-Wiki_lion.jpgbin0 -> 5256 bytes
-rw-r--r--Processing/demolibrary/images/250px-Wildlifephotography.jpgbin0 -> 13062 bytes
-rw-r--r--Processing/demolibrary/images/300px-Lascaux-diverticule-f%C3%A9lins.jpgbin0 -> 13290 bytes
-rw-r--r--Processing/demolibrary/images/300px-Namibie_Etosha_Girafe_01.jpgbin0 -> 42722 bytes
-rw-r--r--Processing/demolibrary/images/80px-India_tiger.jpgbin0 -> 5084 bytes
-rw-r--r--Processing/demolibrary/images/83px-Indischer_Maler_um_1650_%28II%29_001.jpgbin0 -> 6760 bytes
-rw-r--r--Processing/demolibrary/images/84px-Brehms_Het_Leven_der_Dieren_Zoogdieren_Orde_4_Tijger_%28Felis_tigris%29.jpgbin0 -> 3582 bytes
-rw-r--r--Processing/demolibrary/images/97px-Sumatratiger-004.jpgbin0 -> 28721 bytes
-rw-r--r--Processing/demolibrary/lion-wikipedia.dita2131
-rw-r--r--Processing/demolibrary/tiger-wikipedia.dita2100
-rw-r--r--Processing/demolibrary/zebra-wikipedia.dita884
-rw-r--r--Stylesheets/ditastyle.css45
-rw-r--r--Stylesheets/ditastylesheet.xsl92
-rw-r--r--Stylesheets/mapstyle.css46
-rw-r--r--Stylesheets/mapstylesheet.xsl24
-rw-r--r--activity/activity.info8
-rw-r--r--activity/slicelogo.svg37
-rw-r--r--docs/infoslicer-code.odtbin0 -> 31334 bytes
-rw-r--r--docs/infoslicer-directions.odtbin0 -> 36284 bytes
-rw-r--r--docs/infoslicer-guipanes.odtbin0 -> 797684 bytes
-rw-r--r--docs/infoslicer-overview.odtbin0 -> 157981 bytes
-rw-r--r--docs/tutorial-booklet-v9.pdfbin0 -> 671366 bytes
-rw-r--r--docs/tutorial-booklet.odtbin0 -> 667854 bytes
-rw-r--r--setup.py14
-rw-r--r--sugaractivity.py130
152 files changed, 13424 insertions, 0 deletions
diff --git a/GUI_Components/Compound_Widgets/Base_Widgets/Editable_Textbox.py b/GUI_Components/Compound_Widgets/Base_Widgets/Editable_Textbox.py
new file mode 100644
index 0000000..0f2fbe8
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Base_Widgets/Editable_Textbox.py
@@ -0,0 +1,294 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+import cPickle
+import pango
+import copy
+from GUI_Components.Compound_Widgets.Base_Widgets.Textbox import Textbox
+
+SNAP_SENTENCE, SNAP_PARAGRAPH, SNAP_SECTION, SNAP_NONE = range(4)
+
+class Editable_Textbox( Textbox ):
+ """
+ Created by Jonathan Mace
+ This class implements its own special code for dragging and selecting.
+ It has an article class which provides the text buffer, and any modifications
+ to the text buffer are done via the article class.
+ """
+
+ def __init__(self):
+ gtk.TextView.__init__(self)
+ self.set_border_width(1)
+ self.set_cursor_visible(True)
+ self.set_editable(True)
+ self.set_wrap_mode(gtk.WRAP_WORD)
+ self.article = None
+ self.set_mode(SNAP_SENTENCE)
+ self.changed = False
+ self.block = True
+
+ self.selecting = False
+ self.handlers = []
+ self.modify_font(pango.FontDescription('arial 9'))
+ self.ignore_snap_self = True
+ self.drag_source = False
+ self.edited = False
+ self.set_property("left-margin", 5)
+
+ def set_article(self, article):
+ self.article = article
+ self.set_buffer(article.getBuffer())
+
+ def get_article(self):
+ return self.article
+
+ def clear(self):
+ self.article.delete()
+
+ def get_mouse_iter(self, x, y):
+ click_coords = self.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, x, y)
+ mouseClickPositionIter = self.get_iter_at_location(click_coords[0], click_coords[1])
+ return mouseClickPositionIter
+
+ def set_mode(self, snapto):
+ self.snapto = snapto
+
+ def set_buffer(self, buffer):
+ for handler in self.handlers:
+ self.disconnect(handler)
+
+ buffer.connect("changed", self.text_changed, None)
+ gtk.TextView.set_buffer(self, buffer)
+
+ self.handlers = []
+
+ self.handlers.append(self.connect("button-press-event", self.clicked_event, None))
+ self.handlers.append(self.connect("button-release-event", self.unclicked_event, None))
+ self.handlers.append(self.connect("drag_data_get", self.drag_data_get_event, None))
+ self.handlers.append(self.connect("drag_begin", self.drag_begin_event, None))
+ self.handlers.append(self.connect("drag-motion", self.drag_motion_event, None))
+ self.handlers.append(self.connect("drag-drop", self.drag_drop_event, None))
+ self.handlers.append(self.connect("drag-leave", self.drag_leave_event, None))
+ self.handlers.append(self.connect("drag-data-delete", self.drag_data_delete_event, None))
+ self.handlers.append(self.connect("drag_data_received", self.drag_data_received_event, None))
+ self.handlers.append(self.connect("drag-end", self.drag_end_event, None))
+ self.handlers.append(self.connect("motion-notify-event", self.motion_notify, None))
+ self.handlers.append(self.connect("focus-out-event", self.leave_notify, None))
+
+ def text_changed(self, buffer, data):
+ self.changed = True
+ self.selecting = False
+
+ def motion_notify(self, widget, event, data):
+ if not self.ignore_snap_self and self.selecting:
+ """ The following code implements the 'snapping' to sentences etc.
+
+ The base class responds to motion notify events and does some unknown (to me)
+ action which for some reason, must complete, otherwise on some platforms it will
+ stop any more motion notify events.
+
+ So what happens, is the first 'run through' of the motion notify responder emits another
+ motion notify event, ignores it and lets the base class respond to it. Then when control
+ is given back to the first emission, we implement our code. The order of events is:
+
+ 1) motion notify event 1 emitted naturally
+ 2) our class responds to motion notify event 1
+ 3) motion notify event 2 emitted by step 2)
+ 4) our class ignores motion notify event 2
+ 5) the default class acts upon motion notify event 2
+ 6) motion notify event 2 finishes naturally
+ 7) our class does its stuff
+ 8) motion notify event 1 finishes by our class stopping its emission
+
+ """
+
+
+ if self.block == True:
+ self.stop_emission("motion-notify-event")
+ self.block = False
+ self.emit("motion-notify-event", event)
+
+
+
+
+ buf = self.get_buffer()
+ mouseiter = self.get_mouse_iter(int(event.x), int(event.y))
+ article = self.get_article()
+
+ if mouseiter.compare(self.selectionstart) == 1:
+ if self.snapto == SNAP_SENTENCE:
+ selectionstart = article.getSentence(self.selectionstart).getStart()
+ selectionend = article.getSentence(mouseiter).getEnd()
+ if self.snapto == SNAP_PARAGRAPH:
+ selectionstart = article.getParagraph(self.selectionstart).getStart()
+ selectionend = article.getParagraph(mouseiter).getEnd()
+ if self.snapto == SNAP_SECTION:
+ selectionstart = article.getSection(self.selectionstart).getStart()
+ selectionend = article.getSection(mouseiter).getEnd()
+ else:
+ if self.snapto == SNAP_SENTENCE:
+ selectionstart = article.getSentence(mouseiter).getStart()
+ selectionend = article.getSentence(self.selectionstart).getEnd()
+ if self.snapto == SNAP_PARAGRAPH:
+ selectionstart = article.getParagraph(mouseiter).getStart()
+ selectionend = article.getParagraph(self.selectionstart).getEnd()
+ if self.snapto == SNAP_SECTION:
+ selectionstart = article.getSection(mouseiter).getStart()
+ selectionend = article.getSection(self.selectionstart).getEnd()
+ self.scroll_to_iter(mouseiter, 0)
+ article.highlight(selectionstart, selectionend)
+
+ else:
+ self.block = True
+
+ def clicked_event(self, widget, event, data):
+ if event.type == gtk.gdk._2BUTTON_PRESS or event.type == gtk.gdk._3BUTTON_PRESS:
+ self.stop_emission("button_press_event")
+ return
+ if event.button == 3:
+ self.stop_emission("button_press_event")
+ return
+ if self.changed == True:
+ buf = self.get_buffer()
+ article = self.get_article()
+
+ article.checkIntegrity()
+ self.changed = False
+ if not self.get_buffer().get_has_selection():
+ result = self.do_button_press_event(widget, event)
+
+ a = self.article
+ loc_iter = self.get_mouse_iter(int(event.x), int(event.y))
+
+ self.selecting = True
+ self.selectionstart = loc_iter
+ self.stop_emission("button-press-event")
+ return result
+ else:
+ buf = self.get_buffer()
+ bounds = buf.get_selection_bounds()
+ if bounds == ():
+ return
+ start = bounds[0]
+ end = bounds[1]
+ if start.compare(end) == 1:
+ start, end = end, start
+ loc = self.get_mouse_iter(int(event.x), int(event.y))
+ if start.compare(loc) == 1 or loc.compare(end) == 1:
+ self.do_button_press_event(widget, event)
+ a = self.article
+ self.selecting = True
+ self.selectionstart = loc
+ self.stop_emission("button-press-event")
+
+ def leave_notify(self, widget, event, data):
+ if self.changed == True:
+ offset = self.get_buffer().get_property("cursor-position")
+ self.article.checkIntegrity()
+ newbuf = self.article.getBuffer()
+ self.set_buffer(newbuf)
+ self.changed = False
+ iter = newbuf.get_iter_at_offset(offset)
+ newbuf.place_cursor(iter)
+
+ def unclicked_event(self, widget, event, data):
+ if self.snapto != SNAP_NONE:
+ self.article.clearArrow()
+ self.do_button_release_event(widget, event)
+ self.selecting = False
+ return True
+ else:
+ return False
+
+ def drag_begin_event(self, widget, context, data):
+ self.grab_focus()
+ if self.snapto != SNAP_NONE:
+ a = self.article
+ a.rememberSelection()
+ self.drag_source = True
+
+ def drag_drop_event(self, widget, context, x, y, time, data):
+ if self.snapto != SNAP_NONE:
+ self.article.clearArrow()
+ self.set_cursor_visible(True)
+
+ def drag_motion_event(self, widget, drag_context, x, y, time, data):
+ if self.snapto != SNAP_NONE and not self.ignore_snap_self or (not self.drag_source and self.ignore_snap_self):
+ self.delete_on_fail = False
+ self.set_cursor_visible(False)
+ a = self.article
+ loc_iter = self.get_mouse_iter(x, y)
+
+ if self.snapto == SNAP_SENTENCE:
+ a.mark(a.getBestSentence(loc_iter).getStart())
+ #a.markSentence(loc_iter)
+ if self.snapto == SNAP_PARAGRAPH:
+ a.mark(a.getBestParagraph(loc_iter).getStart())
+ #a.markParagraph(loc_iter)
+ if self.snapto == SNAP_SECTION:
+ a.mark(a.getBestSection(loc_iter).getStart())
+ #a.markSection(loc_iter)
+
+ result = self.do_drag_motion(widget, drag_context, x, y, time)
+ self.stop_emission("drag-motion")
+ return result
+ self.changed = False
+ else:
+ self.set_cursor_visible(True)
+ self.drag_source = True
+
+
+ def drag_leave_event(self, widget, context, time, data):
+ if self.snapto != SNAP_NONE and not self.ignore_snap_self or (not self.drag_source and self.ignore_snap_self):
+ self.delete_on_fail = True
+ self.article.clearArrow()
+ self.do_drag_leave(widget, context, time)
+ self.stop_emission("drag-leave")
+ self.changed = False
+ self.set_cursor_visible(True)
+
+ def drag_data_delete_event(self, widget, context, data):
+ if self.snapto != SNAP_NONE and not self.ignore_snap_self or (not self.drag_source and self.ignore_snap_self):
+ a = self.article
+ a.deleteDragSelection()
+ self.stop_emission("drag-data-delete")
+ self.changed = False
+
+ def drag_data_received_event(self, widget, context, x, y, selection_data, info, time, data):
+ if self.snapto != SNAP_NONE and not self.ignore_snap_self or (not self.drag_source and self.ignore_snap_self):
+ a = self.article
+ insert_loc = self.get_mouse_iter(x, y)
+ data_received_type = str(selection_data.type)
+ data = cPickle.loads(str(selection_data.data))
+
+ if data_received_type == "sentence":
+ bestpoint = insert_loc
+ if data_received_type == "paragraph":
+ bestpoint = a.getBestParagraph(insert_loc).getStart()
+ if data_received_type == "section":
+ bestpoint = a.getBestSection(insert_loc).getStart()
+
+ a.insert(data, insert_loc)
+
+ self.stop_emission("drag-data-received")
+ context.finish(True, True, time)
+ self.grab_focus()
+
+ def drag_data_get_event(self, widget, context, selection_data, info, time, data):
+ if not self.ignore_snap_self and self.snapto != SNAP_NONE:
+ a = self.article
+
+ if self.snapto == SNAP_SENTENCE:
+ atom = gtk.gdk.atom_intern("sentence")
+ if self.snapto == SNAP_PARAGRAPH:
+ atom = gtk.gdk.atom_intern("paragraph")
+ if self.snapto == SNAP_SECTION:
+ atom = gtk.gdk.atom_intern("section")
+
+ string = cPickle.dumps(a.getSelection())
+ selection_data.set(atom, 8, string)
+ self.stop_emission("drag-data-get")
+
+ def drag_end_event(self, widget, context, data):
+ self.drag_source = False \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/Base_Widgets/Readonly_Textbox.py b/GUI_Components/Compound_Widgets/Base_Widgets/Readonly_Textbox.py
new file mode 100644
index 0000000..08cae3e
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Base_Widgets/Readonly_Textbox.py
@@ -0,0 +1,180 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+import pango
+import cPickle
+from GUI_Components.Compound_Widgets.Base_Widgets.Textbox import Textbox
+from Processing.IO_Manager import IO_Manager
+
+SELECT_SENTENCE, SELECT_PARAGRAPH, SELECT_SECTION, FULL_EDIT = range(4)
+
+class Readonly_Textbox( Textbox ):
+ """
+ Created by Jonathan Mace
+ This class implements its own special code for dragging and selecting.
+ It has an article class which provides the text buffer, and any modifications
+ to the text buffer are done via the article class.
+ This class is read-only, so it is not editable and will not act as a drag
+ destination.
+ """
+
+ def __init__(self, use_as_drag_source = True):
+ Textbox.__init__(self)
+ self.selecting = False
+ self.use_as_drag_source = use_as_drag_source
+ self.set_mode(SELECT_SENTENCE)
+ self.block = True
+ self.modify_font(pango.FontDescription('arial 9'))
+
+
+ def set_mode(self, mode):
+ self.selectionmode = mode
+ self.disconnect_handlers()
+ if mode == SELECT_SENTENCE: self.__set_select_mode()
+ elif mode == SELECT_PARAGRAPH: self.__set_select_mode()
+ elif mode == SELECT_SECTION: self.__set_select_mode()
+ else: pass
+
+ def __set_select_mode(self):
+ if self.use_as_drag_source == True:
+ self.event_handlers.append(self.connect("button-press-event", self.clicked_event, None))
+ self.event_handlers.append(self.connect("motion-notify-event", self.motion_notify, None))
+ self.event_handlers.append(self.connect("move-cursor", self.move_cursor, None))
+ self.event_handlers.append(self.connect("button-release-event", self.unclicked_event, None))
+ self.event_handlers.append(self.connect("drag_data_get", self.drag_data_get_event, None))
+ self.event_handlers.append(self.connect("drag-data-received", self.drag_data_received, None))
+ self.event_handlers.append(self.connect("drag-motion", self.drag_motion, None))
+
+ def drag_motion(self, widget, context, x, y, timestamp, data):
+ context.drag_status(gtk.gdk.ACTION_COPY, timestamp)
+ return True
+
+ def drag_data_received(self, widget, context, x, y, selection_data, info, time, data):
+ data_received_type = str(selection_data.type)
+ if data_received_type == "article":
+ data = cPickle.loads(str(selection_data.data))
+ title = data[0]
+ theme = data[1]
+ article = IO_Manager().load_article(title, theme)
+ self.set_article(article)
+
+ def clicked_event(self, widget, event, data):
+ if event.type == gtk.gdk._2BUTTON_PRESS or event.type == gtk.gdk._3BUTTON_PRESS:
+ self.stop_emission("button_press_event")
+ return
+ if event.button == 3:
+ self.stop_emission("button_press_event")
+ return
+ if not self.get_buffer().get_has_selection():
+ result = self.do_button_press_event(widget, event)
+
+ a = self.article
+ loc_iter = self.get_mouse_iter(int(event.x), int(event.y))
+
+ self.selecting = True
+ self.selectionstart = loc_iter
+ self.stop_emission("button-press-event")
+ return result
+ else:
+ buf = self.get_buffer()
+ bounds = buf.get_selection_bounds()
+ if bounds == ():
+ return
+ start = bounds[0]
+ end = bounds[1]
+ if start.compare(end) == 1:
+ start, end = end, start
+ loc = self.get_mouse_iter(int(event.x), int(event.y))
+ if start.compare(loc) == 1 or loc.compare(end) == 1:
+ self.do_button_press_event(widget, event)
+ a = self.article
+ self.selecting = True
+ self.selectionstart = loc
+ self.stop_emission("button-press-event")
+
+ def move_cursor(self, widget, stepsize, count, extend, data):
+ if self.selecting:
+ result = self.do_move_cursor(widget, event)
+ self.stop_emission("move-cursor")
+ return result
+
+ def motion_notify(self, widget, event, data):
+ if self.selecting:
+ """ The following code implements the 'snapping' to sentences etc.
+
+ The base class responds to motion notify events and does some unknown (to me)
+ action which for some reason, must complete, otherwise on some platforms it will
+ stop any more motion notify events.
+
+ So what happens, is the first 'run through' of the motion notify responder emits another
+ motion notify event, ignores it and lets the base class respond to it. Then when control
+ is given back to the first emission, we implement our code. The order of events is:
+
+ 1) motion notify event 1 emitted naturally
+ 2) our class responds to motion notify event 1
+ 3) motion notify event 2 emitted by step 2)
+ 4) our class ignores motion notify event 2
+ 5) the default class acts upon motion notify event 2
+ 6) motion notify event 2 finishes naturally
+ 7) our class does its stuff
+ 8) motion notify event 1 finishes by our class stopping its emission
+
+ """
+
+ if self.block == True:
+ self.stop_emission("motion-notify-event")
+ self.block = False
+ self.emit("motion-notify-event", event)
+
+ buf = self.get_buffer()
+ mouseiter = self.get_mouse_iter(int(event.x), int(event.y))
+ article = self.get_article()
+ if mouseiter.compare(self.selectionstart) == 1:
+ if self.selectionmode == SELECT_SENTENCE:
+ selectionstart = article.getSentence(self.selectionstart).getStart()
+ selectionend = article.getSentence(mouseiter).getEnd()
+ if self.selectionmode == SELECT_PARAGRAPH:
+ selectionstart = article.getParagraph(self.selectionstart).getStart()
+ selectionend = article.getParagraph(mouseiter).getEnd()
+ if self.selectionmode == SELECT_SECTION:
+ selectionstart = article.getSection(self.selectionstart).getStart()
+ selectionend = article.getSection(mouseiter).getEnd()
+ else:
+ if self.selectionmode == SELECT_SENTENCE:
+ selectionstart = article.getSentence(mouseiter).getStart()
+ selectionend = article.getSentence(self.selectionstart).getEnd()
+ if self.selectionmode == SELECT_PARAGRAPH:
+ selectionstart = article.getParagraph(mouseiter).getStart()
+ selectionend = article.getParagraph(self.selectionstart).getEnd()
+ if self.selectionmode == SELECT_SECTION:
+ selectionstart = article.getSection(mouseiter).getStart()
+ selectionend = article.getSection(self.selectionstart).getEnd()
+ self.scroll_to_iter(mouseiter, 0)
+ article.highlight(selectionstart, selectionend)
+
+ else:
+ self.block = True
+
+ def unclicked_event(self, widget, event, data):
+ self.article.clearArrow()
+ self.do_button_release_event(widget, event)
+ self.selecting = False
+ self.stop_emission("button-release-event")
+
+ def drag_data_get_event(self, widget, context, selection_data, info, time, data):
+
+ a = self.article
+
+ if self.selectionmode == SELECT_SENTENCE:
+ atom = gtk.gdk.atom_intern("sentence")
+ if self.selectionmode == SELECT_PARAGRAPH:
+ atom = gtk.gdk.atom_intern("paragraph")
+ if self.selectionmode == SELECT_SECTION:
+ atom = gtk.gdk.atom_intern("section")
+
+ string = cPickle.dumps(a.getSelection())
+ selection_data.set(atom, 8, string)
+ self.stop_emission("drag-data-get")
+ self.set_editable(False)
+ \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/Base_Widgets/Textbox.py b/GUI_Components/Compound_Widgets/Base_Widgets/Textbox.py
new file mode 100644
index 0000000..95f0681
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Base_Widgets/Textbox.py
@@ -0,0 +1,56 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+import cPickle
+import pango
+
+SELECT_SENTENCE, SELECT_PARAGRAPH, SELECT_SECTION, FULL_EDIT = range(4)
+
+class Textbox( gtk.TextView ):
+ """
+ Created by Jonathan Mace
+ The Textbox class is the base class for our own custom textboxes which implement
+ the snapping to sentences/paragraphs/sections. The two subclasses are:
+ Editable_Textbox - this is a textbox with full editing features
+ Readonly_Textbox - this textbox is not editable and will not respond to
+ drags.
+ """
+
+
+ def __init__(self):
+ gtk.TextView.__init__(self)
+ self.set_border_width(1)
+ self.event_handlers = []
+ self.set_wrap_mode(gtk.WRAP_WORD)
+ self.set_cursor_visible(False)
+ self.set_editable(False)
+ self.modify_font(pango.FontDescription('arial 9'))
+ self.article = None
+ self.set_property("left-margin", 5)
+
+ def set_article(self, article):
+ self.article = article
+ self.set_buffer(article.getBuffer())
+
+ def get_article(self):
+ return self.article
+
+ def show(self):
+ gtk.TextView.show(self)
+
+ def clear(self):
+ self.article.delete()
+
+ def disconnect_handlers(self):
+ self.set_editable(False)
+ self.set_cursor_visible(False)
+ for handler in self.event_handlers:
+ self.disconnect(handler)
+ self.event_handlers = []
+
+ def get_mouse_iter(self, x, y):
+ # Convenience method to get the iter in the buffer of x, y coords.
+ click_coords = self.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, x, y)
+ mouseClickPositionIter = self.get_iter_at_location(click_coords[0], click_coords[1])
+ return mouseClickPositionIter \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/Base_Widgets/__init__.py b/GUI_Components/Compound_Widgets/Base_Widgets/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Base_Widgets/__init__.py
diff --git a/GUI_Components/Compound_Widgets/Editing_View.py b/GUI_Components/Compound_Widgets/Editing_View.py
new file mode 100644
index 0000000..a8511ba
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Editing_View.py
@@ -0,0 +1,50 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Compound_Widgets.Base_Widgets.Editable_Textbox import Editable_Textbox
+
+class Editing_View( gtk.VBox ):
+ """
+ Created by Jonathan Mace
+ This class wraps an editable textbox into a scrollable window and
+ gives it a title.
+ """
+ def __init__(self):
+ gtk.VBox.__init__(self)
+ self.set_border_width(0)
+ self.set_spacing(2)
+
+ labeleb = gtk.EventBox()
+ labeleb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#EEEEEE"))
+ self.pack_start(labeleb, False, False, 0)
+ labeleb.show()
+
+ self.articletitle = gtk.Label()
+ self.articletitle.set_justify(gtk.JUSTIFY_CENTER)
+ labeleb.add(self.articletitle)
+ self.articletitle.show()
+
+ self.textwindow = gtk.ScrolledWindow()
+ self.textwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.pack_start(self.textwindow)
+ self.textwindow.show()
+
+ self.textbox = Editable_Textbox()
+ self.textwindow.add(self.textbox)
+ self.textbox.show()
+
+ def set_sentence_selection_mode(self):
+ self.textbox.set_mode(0)
+
+ def set_paragraph_selection_mode(self):
+ self.textbox.set_mode(1)
+
+ def set_section_selection_mode(self):
+ self.textbox.set_mode(2)
+
+ def set_full_edit_mode(self):
+ self.textbox.set_mode(3)
+
+ def clear_contents(self):
+ self.textbox.clear() \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/Gallery_View.py b/GUI_Components/Compound_Widgets/Gallery_View.py
new file mode 100644
index 0000000..6cd8b10
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Gallery_View.py
@@ -0,0 +1,176 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+import cPickle
+from Processing.IO_Manager import IO_Manager
+from GUI_Components.Compound_Widgets.Base_Widgets.Editable_Textbox import Editable_Textbox
+from Processing.Article.Article_Data import *
+from Processing.Article.Article import Article
+
+class Gallery_View( gtk.HBox ):
+ """
+ Created by Christopher Leonard
+ Drag-and-drop methods added by Jonathan Mace
+
+ The gallery view acts in the same was as the Reading_View
+ except instead of displaying the text of an article, it
+ displays the images associated with that article, in a scrollable display.
+
+
+ Drag-and-drop methods have been added to set up the images as a drag
+ source.
+ The data returned by drag-data-get will be a list containing
+ an Image_Data object and a Sentence_Data object.
+ These correspond to the image
+ and caption respectively.
+ """
+
+ def __init__(self):
+ self.theme = None
+ self.image_list = []
+ gtk.HBox.__init__(self)
+
+ self.current_index = -1
+
+ left_button = gtk.Button(label="\n\n << \n\n")
+
+ right_button = gtk.Button(label="\n\n >> \n\n")
+
+ self.imagenumberlabel = gtk.Label()
+
+ self.image = gtk.Image()
+
+ self.imagebox = gtk.EventBox()
+ self.imagebox.add(self.image)
+
+ self.imagebox.drag_source_set(gtk.gdk.BUTTON1_MASK, [("text/plain", gtk.TARGET_SAME_APP, 80)], gtk.gdk.ACTION_COPY)
+ self.imagebox.connect("drag-begin", self.drag_begin_event, None)
+ self.imagebox.connect("drag-data-get", self.drag_data_get_event, None)
+
+ self.caption = gtk.Label("")
+ self.caption.set_line_wrap(True)
+
+ self.image_drag_container = gtk.VBox()
+ self.image_drag_container.pack_start(self.imagenumberlabel, expand = False)
+ self.image_drag_container.pack_start(self.imagebox, expand=False)
+ self.image_drag_container.pack_start(self.caption, expand=False)
+
+ self.articlemenu = gtk.combo_box_new_text()
+ self.articlemenu.connect("changed", self.source_selected, None)
+
+ image_container = gtk.VBox()
+ image_container.pack_start(self.articlemenu, expand=False)
+ image_container.pack_start(gtk.Label(" "))
+ image_container.pack_start(self.image_drag_container, expand=False)
+ image_container.pack_start(gtk.Label(" "))
+
+ left_button_container = gtk.VBox()
+ left_button_container.pack_start(gtk.Label(" "))
+ left_button_container.pack_start(left_button, expand=False)
+ left_button_container.pack_start(gtk.Label(" "))
+
+ right_button_container = gtk.VBox()
+ right_button_container.pack_start(gtk.Label(" "))
+ right_button_container.pack_start(right_button, expand=False)
+ right_button_container.pack_start(gtk.Label(" "))
+
+
+ self.pack_start(left_button_container, expand=False)
+ self.pack_start(image_container)
+ self.pack_start(right_button_container, expand=False)
+
+ self._source_article = None
+ self.show_all()
+ right_button.connect("clicked", self.get_next_item, None)
+ left_button.connect("clicked", self.get_prev_item, None)
+ self.get_next_item(right_button, None)
+
+ self.source_article_id = 0
+ if self.theme == None:
+ self.caption.set_text("No theme has been selected, please return to the lirary")
+
+ def insert_new_theme(self, widget, entry):
+ pass
+
+ def get_next_item(self, button, param):
+ if self.image_list == []:
+ if self._source_article and self._source_article.article_title:
+ self.caption.set_text("This article does not have any images")
+ else:
+ self.caption.set_text("Please select a Wikipedia article from the menu above")
+ self.image.clear()
+ return
+ self.current_index += 1
+ if self.current_index == len(self.image_list):
+ self.current_index = 0
+ self.imagebuf = gtk.gdk.pixbuf_new_from_file(self.image_list[self.current_index][0])
+ self.image.set_from_pixbuf(self.imagebuf)
+ self.caption.set_text("\n" + self.image_list[self.current_index][1])
+ self.imagenumberlabel.set_text("(%d / %d)\n" % (self.current_index+1, len(self.image_list)))
+
+ def get_prev_item(self, button, param):
+ if self.image_list == []:
+ if self._source_article and self._source_article.article_title:
+ self.caption.set_text("This article does not have any images")
+ else:
+ self.caption.set_text("Please select a Wikipedia article from the menu above")
+ self.image.clear()
+ return
+ if self.current_index == 0:
+ self.current_index = len(self.image_list)
+ self.current_index -= 1
+ self.imagebuf = gtk.gdk.pixbuf_new_from_file(self.image_list[self.current_index][0])
+ self.image.set_from_pixbuf(self.imagebuf)
+ self.caption.set_text("\n" + self.image_list[self.current_index][1])
+ self.imagenumberlabel.set_text("(%d / %d)\n" % (self.current_index+1, len(self.image_list)))
+
+ def get_first_item(self):
+ if self.image_list == []:
+ if self._source_article and self._source_article.article_title:
+ self.caption.set_text("This article does not have any images")
+ else:
+ self.caption.set_text("Please select a Wikipedia article from the menu above")
+ self.image.clear()
+ return
+ self.current_index = 0
+ self.imagebuf = gtk.gdk.pixbuf_new_from_file(self.image_list[self.current_index][0])
+ self.image.set_from_pixbuf(self.imagebuf)
+ self.caption.set_text("\n" + self.image_list[self.current_index][1])
+ print "setting text to:"
+ print "(%d / %d)\n" % (self.current_index+1, len(self.image_list))
+ self.imagenumberlabel.set_text("(%d / %d)\n" % (self.current_index+1, len(self.image_list)))
+
+ def set_image_list(self, image_list):
+ print "validagting image list"
+ self.image_list = IO_Manager().validate_image_list(image_list)
+ print self.image_list
+
+ def source_selected(self, combobox, param):
+ if combobox.get_active_text() == None :
+ return
+ if self.theme == None:
+ print "no theme set, defaulting to Wikipedia Articles"
+ self.theme = "Wikipedia Articles"
+ if self._source_article.article_title == combobox.get_active_text():
+ return
+ self._source_article = IO_Manager().load_article(combobox.get_active_text(), self.theme)
+ self.set_image_list(self._source_article.image_list)
+ self.get_first_item()
+
+
+ def drag_begin_event(self, widget, context, data):
+ self.imagebox.drag_source_set_icon_pixbuf(self.imagebuf)
+
+ def drag_data_get_event(self, widget, context, selection_data, info, timestamp, data):
+ print "getting data"
+ atom = gtk.gdk.atom_intern("section")
+ imagedata = Picture_Data(self.source_article_id, self.image_list[self.current_index][0])
+ captiondata = Sentence_Data(0, self.source_article_id, 0, 0, 0, self.image_list[self.current_index][1])
+ paragraph1data = Paragraph_Data(0, self.source_article_id, 0, 0, [imagedata])
+ paragraph2data = Paragraph_Data(0, self.source_article_id, 0, 0, [captiondata])
+ sectionsdata = [Section_Data(0, self.source_article_id, 0, [paragraph1data, paragraph2data])]
+ string = cPickle.dumps(sectionsdata)
+ selection_data.set(atom, 8, string)
+
+
diff --git a/GUI_Components/Compound_Widgets/Library_View.py b/GUI_Components/Compound_Widgets/Library_View.py
new file mode 100644
index 0000000..f28220d
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Library_View.py
@@ -0,0 +1,1141 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+import pango
+import cPickle
+import time
+from threading import Timer
+from Processing.IO_Manager import *
+from Processing.Article.Article import Article
+from Processing.Article.Article_Data import *
+from GUI_Components.Compound_Widgets.Base_Widgets.Readonly_Textbox import Readonly_Textbox
+
+theme_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c #62F24D",
+"G c black",
+" .......... ",
+" .gggggggg. ",
+" ..........g. ",
+" .gggggggg.g. ",
+" ..........g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGgggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGGGGg.g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGGGGg.g.g. ",
+" .gggggggg.g... ",
+" .gGGGGGGg.g. ",
+" .gggggggg... ",
+" .gGGGGGGg. ",
+" .......... "]
+
+newtheme_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c white",
+"G c black",
+" .......... ",
+" .gggggggg. ",
+" ..........g. ",
+" .gggggggg.g. ",
+" ..........g.g. ",
+" .gggggggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gggggggg.g... ",
+" .gggggggg.g. ",
+" .gggggggg... ",
+" .gggggggg. ",
+" .......... "]
+
+wikitheme_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c #FC8B65",
+"G c black",
+" .......... ",
+" .gggggggg. ",
+" ..........g. ",
+" .gggggggg.g. ",
+" ..........g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGgggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGGGGg.g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGGGGg.g.g. ",
+" .gggggggg.g... ",
+" .gGGGGGGg.g. ",
+" .gggggggg... ",
+" .gGGGGGGg. ",
+" .......... "]
+
+mytheme_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c #E6E6E6",
+"G c #080808",
+" .......... ",
+" .gggggggg. ",
+" ..........g. ",
+" .gggggggg.g. ",
+" ..........g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGgggg.g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGGGGg.g.g. ",
+" .gggggggg.g.g. ",
+" .gGGGGGGg.g.g. ",
+" .gggggggg.g... ",
+" .gGGGGGGg.g. ",
+" .gggggggg... ",
+" .gGGGGGGg. ",
+" .......... "]
+
+article_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c #62F24D",
+"G c black",
+" ............ ",
+" .gggggggggg. ",
+" .GGGGgggggg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" ............ ",
+]
+
+newarticle_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c white",
+"G c black",
+" ............ ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" .gggggggggg. ",
+" ............ ",
+]
+
+wikiarticle_xpm = [
+"16 16 4 1",
+" c None s None",
+". c black",
+"g c #FC8B65",
+"G c black",
+" ............ ",
+" .gggggggggg. ",
+" .GGGGgggggg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" .gggggggggg. ",
+" .gGGGGGGGGg. ",
+" ............ ",
+]
+
+
+class Library_View( gtk.HBox ):
+ """
+ Created by: Jonathan Mace
+
+ Library View sets up the view to the library.
+ It consists of 3 main widgets:
+ 1) Treeview widget
+ This is populated with the themes and articles in the library.
+ They can be renamed, new articles and themes can be added, and
+ they can be moved about with drag and drop.
+ 2) Source-view widget
+ This widget displays the current source article. It is a drag
+ destination for drags originating from the treeview. Upon receiving
+ a drag, it will load the appropriate article
+ 3) Edit-view widget
+ This widget displays the current edit article. It acts the same
+ way as the source-view widget.
+
+ A few minor things also exist, such as the creation of new blank articles
+ and new blank themes if the user goes to editing mode without having anything
+ selected.
+
+ There is also a method for downloading new articles into the currently selected
+ theme, which is activated by a button in the toolbar which is set up in the
+ Library_Pane class.
+
+ """
+
+ # Create the icons
+ themeicon = gtk.gdk.pixbuf_new_from_xpm_data(theme_xpm)
+ articleicon = gtk.gdk.pixbuf_new_from_xpm_data(article_xpm)
+ newarticleicon = gtk.gdk.pixbuf_new_from_xpm_data(newarticle_xpm)
+ newthemeicon = gtk.gdk.pixbuf_new_from_xpm_data(newtheme_xpm)
+ wikithemeicon = gtk.gdk.pixbuf_new_from_xpm_data(wikitheme_xpm)
+ wikiarticleicon = gtk.gdk.pixbuf_new_from_xpm_data(wikiarticle_xpm)
+ mythemeicon = gtk.gdk.pixbuf_new_from_xpm_data(mytheme_xpm)
+
+ def __init__(self):
+ self.ignore = True
+
+ gtk.HBox.__init__(self)
+
+ # First things first - make it look nice depending on the platform
+ running_on = platform.system()
+ self.colwidth = 250
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ self.colwidth = 350
+
+
+ #self.set_homogeneous(True)
+ self.set_spacing(2)
+ self.set_border_width(1)
+
+ # Create the tree view, pack and show it
+ self.treestore, self.treeview = self.__create_tree()
+ self.treestorecontainer = gtk.ScrolledWindow()
+ self.treestorecontainer.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.treestorecontainer.add(self.treeview)
+ self.pack_start(self.treestorecontainer, False, False, 1)
+ self.treestorecontainer.set_size_request(self.colwidth, -1)
+ self.treestorecontainer.show_all()
+
+ # Create a box for the textviews at the top and the status bar at the bottom
+ maindisplay = gtk.VBox()
+ maindisplay.set_spacing(2)
+ self.pack_start(maindisplay)
+ maindisplay.show()
+
+ # Create a box for the two text views
+ textviewbox = gtk.HBox()
+ textviewbox.set_spacing(3)
+ textviewbox.set_homogeneous(True)
+ maindisplay.pack_start(textviewbox)
+ textviewbox.show()
+
+ # Create the status bar at the bottom of the page
+
+ # Not bothering to show the statusbar
+ statuseb = gtk.EventBox()
+ statuseb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#EEEEEE"))
+ maindisplay.pack_start(statuseb, False, True, 0)
+ statuseb.set_size_request(-1, 50)
+ statuseb.show()
+
+ self.statusbar = gtk.Label()
+ statuseb.add(self.statusbar)
+ self.statusbar.show()
+
+ # Create the sourcepane label and textbox
+ self.sourcepanebox = gtk.VBox()
+ self.sourcepanebox.set_spacing(2)
+ textviewbox.pack_start(self.sourcepanebox)
+ self.sourcepanebox.show()
+
+ labeleb = gtk.EventBox()
+ labeleb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#EEEEEE"))
+ self.sourcepanebox.pack_start(labeleb, False, False, 0)
+ labeleb.show()
+
+ self.sourcepanelabel = gtk.Label()
+ self.sourcepanelabel.set_justify(gtk.JUSTIFY_CENTER)
+ self.sourcepanelabel.set_markup("<b>Wikipedia Article:</b>\n ")
+ labeleb.add(self.sourcepanelabel)
+ self.sourcepanelabel.show()
+
+
+ sourcetextbox = gtk.ScrolledWindow()
+ sourcetextbox.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.sourcepanebox.pack_start(sourcetextbox)
+ sourcetextbox.show()
+
+ self.sourcetext = Readonly_Textbox(False)
+ self.sourcetext.set_editable(False)
+ self.sourcetext.set_cursor_visible(False)
+ self.sourcetext.connect("button-press-event", self.suppress, None)
+ sourcetextbox.add(self.sourcetext)
+ self.sourcetext.modify_font(pango.FontDescription('arial 9'))
+ self.sourcetext.show()
+ self.sourcetext.drag_dest_set(gtk.DEST_DEFAULT_ALL, [("sourcearticle", gtk.TARGET_SAME_APP, 0)], gtk.gdk.ACTION_COPY)
+
+
+ # Create the editpane label and textbox
+ self.editpanebox = gtk.VBox()
+ self.editpanebox.set_spacing(2)
+ textviewbox.pack_start(self.editpanebox)
+ self.editpanebox.show()
+
+ labeleb = gtk.EventBox()
+ labeleb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#EEEEEE"))
+ self.editpanebox.pack_start(labeleb, False, False, 0)
+ labeleb.show()
+
+ self.editpanelabel = gtk.Label()
+ self.editpanelabel.set_justify(gtk.JUSTIFY_CENTER)
+ self.editpanelabel.set_markup("<b>My Article:</b>\n ")
+ labeleb.add(self.editpanelabel)
+ self.editpanelabel.show()
+
+ edittextbox = gtk.ScrolledWindow()
+ edittextbox.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.editpanebox.pack_start(edittextbox)
+ edittextbox.show()
+
+ self.edittext = Readonly_Textbox(False)
+ self.edittext.set_editable(False)
+ self.edittext.set_cursor_visible(False)
+ self.edittext.connect("button-press-event", self.suppress, None)
+ edittextbox.add(self.edittext)
+ self.edittext.modify_font(pango.FontDescription('arial 9'))
+ self.edittext.show()
+ self.edittext.drag_dest_set(gtk.DEST_DEFAULT_ALL, [("editarticle", gtk.TARGET_SAME_APP, 0)], gtk.gdk.ACTION_COPY)
+
+
+
+ def suppress(self, widget, event, data):
+ widget.stop_emission("button-press-event")
+
+ def __create_tree(self):
+ """
+ Written by: Jonathan Mace
+ Last Modified: 22/08/2008
+ This method sets up the tree structure used to browse topics and articles.
+ It populates the treemodel, connects all the events together and then returns the treeview widget.
+ """
+
+ # Create and populate the treestore.
+ # The first element is the text (so, topic title or article title).
+ # The second element is the associated icon.
+ # The third element is the type (so, theme or article)
+ treestore = gtk.TreeStore(str, gtk.gdk.Pixbuf, str, str, bool)
+ themes = IO_Manager().get_themes()
+ if not "Wikipedia Articles" in themes:
+ IO_Manager().add_theme_to_library("Wikipedia Articles")
+ themes.append("Wikipedia Articles")
+ if not "My Articles" in themes:
+ IO_Manager().add_theme_to_library("My Articles")
+ themes.append("My Articles")
+
+ for theme in themes:
+ if theme == "Wikipedia Articles":
+ themeiter = treestore.append(None, ["<b>%s</b>" % (theme, ), self.wikithemeicon, "wikitheme", "aaaaaaaaaaaaaaaaaaa", False])
+ articles = IO_Manager().get_pages_in_theme(theme)
+ for article in articles:
+ treestore.append(themeiter, [article, self.wikiarticleicon, "wikiarticle", article, False])
+ elif theme == "My Articles":
+ themeiter = treestore.append(None, ["<b>%s</b>" % (theme, ), self.mythemeicon, "mytheme", "aaaaaaaaaaaaaaaaaab", False])
+ articles = IO_Manager().get_pages_in_theme(theme)
+ for article in articles:
+ treestore.append(themeiter, [article, self.articleicon, "article", article, True])
+ treestore.append(themeiter, ["<i>Create new article</i>", self.newarticleicon, "newarticle", "aaaaaaaaaaaaaaaaaaaa", True])
+ else:
+ themeiter = treestore.append(None, ["<b>%s</b>" % (theme, ), self.themeicon, "theme", theme, True])
+ articles = IO_Manager().get_pages_in_theme(theme)
+ for article in articles:
+ treestore.append(themeiter, [article, self.articleicon, "article", article, True])
+ treestore.append(themeiter, ["<i>Create new article</i>", self.newarticleicon, "newarticle", "aaaaaaaaaaaaaaaaaaaa", True])
+ treestore.append(None, ["<i>Create new theme</i>", self.newthemeicon, "newtheme", "zzzzzzzzzzzzzzzzz", True])
+ treestore.set_sort_column_id(3, gtk.SORT_ASCENDING)
+
+ # Create the treeview, set properties.
+ treeview = gtk.TreeView(treestore)
+ treeview.set_enable_search(False)
+ treeview.set_headers_visible(False)
+ treeview.set_reorderable(False)
+ treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, [('text/plain', 0, 0), ("sourcearticle", gtk.TARGET_SAME_APP, 0), ("editarticle", gtk.TARGET_SAME_APP, 0)], gtk.gdk.ACTION_MOVE | gtk.gdk.ACTION_COPY)
+ treeview.enable_model_drag_dest([('text/plain', 0, 0)], gtk.gdk.ACTION_MOVE)
+ treeview.connect("drag-begin", self.drag_begin_event, None)
+ treeview.connect("drag-drop", self.drag_drop_event, None)
+ treeview.connect("drag-data-get", self.drag_data_get_event, None)
+ treeview.connect("key-press-event", self.key_pressed, None)
+
+ # Create the column to show the data, add to the treeview
+ column = gtk.TreeViewColumn()
+ treeview.append_column(column)
+
+ # Create the cell renderers. Set properties and add to the column
+ iconcell = gtk.CellRendererPixbuf()
+
+ cell = gtk.CellRendererText()
+ cell.connect("edited", self.name_changed, None)
+
+
+ column.pack_start(iconcell, False)
+ column.set_attributes(iconcell, pixbuf=1)
+ column.set_sort_column_id(0)
+
+ column.pack_start(cell, True)
+ cell.set_property("editable", True)
+ column.set_attributes(cell, markup=0)
+
+ path = (0, )
+ iter = treestore.get_iter(path)
+ path = treestore.get_path(iter)
+ treeview.expand_to_path(path)
+
+ return treestore, treeview
+
+
+ def populate(self):
+ # Remove and destroy the current contents of the panel
+ self.remove(self.treestorecontainer)
+ self.treestorecontainer.destroy()
+
+ # Create the new tree view, pack and show it
+ self.treestore, self.treeview = self.__create_tree()
+ self.treestorecontainer = gtk.ScrolledWindow()
+ self.treestorecontainer.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.treestorecontainer.set_size_request(self.colwidth, -1)
+ self.treestorecontainer.add(self.treeview)
+ self.pack_start(self.treestorecontainer, False, False, 0)
+ self.reorder_child(self.treestorecontainer, 0)
+ self.treestorecontainer.show_all()
+
+ def add_theme_to_tree(self, theme):
+ """ Adds a row to the tree with name 'theme'
+ Note, that this does not save anything in the IO Manager
+ """
+ model = self.treestore
+ model.append(None, ["<b>" + theme + "</b>", self.themeicon, "theme", theme, True])
+
+ def add_article_to_tree(self, theme, title):
+ """ Adds a row to the tree under theme 'theme' with title 'title'
+ Note, that this does not save anything in the IO Manager
+ A typical usage of this would be:
+
+ IO_Manager().save_article(article)
+ Library_View.add_article_to_tree(article.article_theme, article.article_title)
+ Library_View.highlight_article(article.article_theme, article.article_title)
+ """
+ theme = "<b>%s</b>"%(theme,)
+ model = self.treestore
+ iter = model.get_iter_first()
+ while iter != None:
+ if model.get(iter, 0)[0] == theme:
+ if theme == "Wikipedia Articles":
+ model.append(iter, [title, self.wikiarticleicon, "wikiarticle", title, True])
+ else:
+ model.append(iter, [title, self.articleicon, "article", title, True])
+ return
+ else:
+ iter = model.iter_next(iter)
+
+ def article_exists_in_tree(self, theme, title):
+ """ Returns true if the article specified exists in the tree structure.
+ This is different to whether it exists as said by IO manager.
+ Typical usage would be:
+
+ IO_Manager().save_article(article)
+ if not Library_View.article_exists_in_tree(article.article_theme, article.article_title):
+ Library_View.add_article_to_tree(article.article_theme, article.article_title)
+ Library_View.highlight_article(article.article_theme, article.article_title)
+
+
+
+ """
+
+ theme = "<b>%s</b>"%(theme,)
+ iter = self.treestore.get_iter_first()
+ while iter != None:
+ if self.treestore.get(iter, 0)[0] == theme:
+ break
+ else:
+ iter = self.treestore.iter_next(iter)
+ if iter == None:
+ return False
+ iter = self.treestore.iter_children(iter)
+ while iter != None:
+ if self.treestore.get(iter, 0)[0] == title:
+ return True
+ else:
+ iter = self.treestore.iter_next(iter)
+ return False
+
+
+ def highlight_theme(self, title):
+ # Highlights the theme specified by title
+ title = "<b>%s</b>"%(title,)
+ iter = self.treestore.get_iter_first()
+ while iter != None:
+ if self.treestore.get(iter, 0)[0] == title:
+ destpath = self.treestore.get_path(iter)
+ self.treeview.set_cursor(destpath, None, True)
+ return
+ else:
+ iter = self.treestore.iter_next(iter)
+
+ def highlight_article(self, theme, title):
+ # Expands the theme specified by theme and highlights
+ # the article within this theme, specified by title.
+ theme = "<b>%s</b>"%(theme,)
+ iter = self.treestore.get_iter_first()
+ while iter != None:
+ if self.treestore.get(iter, 0)[0] == theme:
+ break
+ else:
+ iter = self.treestore.iter_next(iter)
+ if iter == None:
+ return
+ iter = self.treestore.iter_children(iter)
+ while iter != None:
+ if self.treestore.get(iter, 0)[0] == title:
+ destpath = self.treestore.get_path(iter)
+ self.treeview.expand_to_path(destpath)
+ self.treeview.set_cursor(destpath, None, True)
+ return
+ else:
+ iter = self.treestore.iter_next(iter)
+
+ def get_current_selection_type(self):
+ # Returns one of 'article', 'newarticle', 'theme', 'newtheme' or None
+ # depending on which element of the tree is selected.
+ model, sourceiter = self.treeview.get_selection().get_selected()
+ if sourceiter == None:
+ return None
+ else:
+ type = model.get(sourceiter, 2)
+ return type
+
+ def get_current_theme(self):
+ # Returns the current theme if one is selected,
+ # otherwise returns none.
+ model, sourceiter = self.treeview.get_selection().get_selected()
+ if sourceiter == None:
+ return None
+ title, type = model.get(sourceiter, 0, 2)
+ if type == "theme" or type == "wikitheme" or type == "mytheme":
+ return title[3:len(title)-4]
+ elif type == "article" or type == "newarticle" or type == "wikiarticle":
+ theme = model.get(model.get_iter(model.get_path(sourceiter)[0]), 0)[0]
+ theme = theme[3:len(theme)-4]
+ return theme
+ else:
+ return None
+
+ def get_current_article(self):
+ # Returns the current article if one is selected,
+ # otherwise returns none.
+ model, sourceiter = self.treeview.get_selection().get_selected()
+ if sourceiter == None:
+ return None
+ title, type = model.get(sourceiter, 0, 2)
+ if type == "article" or type == "wikiarticle":
+ return title
+ else:
+ return None
+
+ def set_status(self, status):
+ pass
+
+
+ def key_pressed(self, widget, event, data):
+ # We want the delete key to do something.
+ key = event.keyval
+ if key == 65535 or key == 65288 or key == 65307:
+ model, sourceiter = self.treeview.get_selection().get_selected()
+ if sourceiter == None:
+ return
+ data = model.get(sourceiter, 0, 1, 2)
+ title = data[0]
+ type = data[2]
+
+ if type == "newarticle" or type == "newtheme" or type == "mytheme" or type == "wikitheme":
+ # If the current selection is a "Create new article" or "Create new theme" field then we ignore the keypress
+ return
+
+ if type == "article" or type == "wikiarticle":
+ title = data[0]
+ theme = model.get(model.get_iter(model.get_path(sourceiter)[0]), 0)[0]
+ theme = theme[3:len(theme)-4]
+
+ # Delete the article from the theme
+ IO_Manager().remove_page(title, theme)
+
+ # If the source/working articles are this one then we remove them
+ source = self.sourcetext.get_article()
+ working = self.edittext.get_article()
+ if source != None and source.article_title == title and source.article_theme == theme:
+ self.sourcepanelabel.set_markup("<b>Wikipedia Article:</b>\n ")
+ self.sourcetext.set_article(Article())
+ if working != None and working.article_title == title and working.article_theme == theme:
+ self.editpanelabel.set_markup("<b>My Article:</b>\n ")
+ self.edittext.set_article(Article())
+
+ # Remove the article from the tree view
+ self.treestore.remove(sourceiter)
+
+ # Highlight the theme
+ destpath = self.treestore.get_path(sourceiter)
+ if destpath == None:
+ self.highlight_theme(theme)
+ else:
+ self.treeview.set_cursor(destpath, None, True)
+
+ elif type == "theme":
+ theme = data[0]
+ theme = theme[3:len(theme)-4]
+
+ # Delete the theme from the filesystem
+ IO_Manager().remove_theme(theme)
+
+ # Remove the theme from the tree view
+ destpath = self.treestore.get_path(sourceiter)
+ self.treestore.remove(sourceiter)
+
+ # If the source/working articles are in this theme then we remove them
+ source = self.sourcetext.get_article()
+ working = self.edittext.get_article()
+ if working != None and working.article_theme == theme:
+ self.editpanelabel.set_markup("<b>My Article:</b>\n ")
+ self.edittext.set_article(Article())
+
+ # Highlight the next theme
+ if destpath != None:
+ self.treeview.set_cursor(destpath, None, True)
+
+ self.set_status("Theme %s deleted" % (theme, ))
+
+
+ def name_changed(self, renderer, path, newtext, data):
+ # Disallowed chars are < > and &
+ if newtext == "" or newtext.isspace() or '&' in newtext or '<' in newtext or '>' in newtext:
+ return
+
+ newtext = newtext
+ model, sourceiter = self.treeview.get_selection().get_selected()
+ data = model.get(sourceiter, 0, 1, 2)
+ title = data[0]
+ type = data[2]
+ if type == "article":
+ """ Rename the selected article """
+
+ # Find the source theme and strip formatting tags
+ sourcetheme = model.get(model.get_iter(model.get_path(sourceiter)[0]), 0)[0]
+ sourcetheme = sourcetheme[3:len(sourcetheme)-4]
+
+ # Reset the name in the source/working articles if appropriate
+ source = self.sourcetext.get_article()
+ edit = self.edittext.get_article()
+ if source and source.article_title == title and source.article_theme == sourcetheme:
+ print "setting source title"
+ source.article_title = newtext
+ self.sourcepanelabel.set_markup("<b>Copy from: </b> %s\n "%(newtext, ))
+ if edit and edit.article_title == title and edit.article_theme == sourcetheme:
+ print "setting edit title"
+ edit.article_title = newtext
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%(sourcetheme, newtext))
+
+ # If there is already an article with the new name in the theme, then we ignore the name change and highlight the existing article
+ if IO_Manager().page_exists(newtext, sourcetheme):
+ self.highlight_article(sourcetheme, newtext)
+ return
+
+ # Rename the page with IO Manager
+ IO_Manager().rename_page(sourcetheme, title, newtext)
+
+ # Set text on row to new text
+ iter = model.get_iter(path)
+ model.set(iter, 0, newtext)
+ model.sort_column_changed()
+ self.set_status("Article %s renamed to %s in theme %s" % (title, newtext, sourcetheme))
+ elif type == "theme":
+ """ Rename the selected theme """
+
+ # Strip formatting tags
+ title = title[3:len(title)-4]
+
+ # Reset the theme in the source/working articles if appropriate
+ source = self.sourcetext.get_article()
+ edit = self.edittext.get_article()
+ if source and source.article_theme == title:
+ print "setting source theme"
+ source.article_theme = newtext
+ if edit and edit.article_theme == title:
+ print "setting edit theme"
+ edit.article_theme = newtext
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%(edit.article_theme, edit.article_title))
+
+ # If there is already a theme with the new name, then we ignore the name change and highlight the existing theme
+ if IO_Manager().theme_exists(newtext):
+ self.highlight_theme(newtext)
+ return
+
+ # Rename theme in IO Manager
+ IO_Manager().rename_theme(title, newtext)
+
+ # Set text on row to the new text (otherwise it would revert back)
+ iter = model.get_iter(path)
+ model.set(iter, 0, "<b>%s</b>"%(newtext,))
+ model.sort_column_changed()
+ self.set_status("Theme %s renamed to %s" % (title, newtext))
+ elif type == "newarticle":
+
+ """ Creating a new article """
+
+ if newtext.find("Create new article") != -1:
+ # If the contents of the text box haven't changed, then
+ # we don't want to do anything.
+ return
+
+ # Find the source theme and strip formatting tags
+ sourceiter = model.get_iter(model.get_path(sourceiter)[0])
+ sourcetheme = model.get(sourceiter, 0)[0]
+ sourcetheme = sourcetheme[3:len(sourcetheme)-4]
+
+ # If there is already a page with the title, we ignore the new article request and highlight the existing article
+ if IO_Manager().page_exists(newtext, sourcetheme):
+ self.highlight_article(sourcetheme, newtext)
+ return
+
+ # Create blank article
+ data = Article_Data(self, article_title = newtext, article_theme = sourcetheme)
+ article = Article(data)
+
+ # Save article with IO manager
+ IO_Manager().save_article(article)
+
+ # Add new row for article
+ destiter = model.append(sourceiter, [newtext, self.articleicon, "article", newtext, True])
+
+ # Highlight new row
+ destpath = model.get_path(destiter)
+ self.treeview.set_cursor(destpath, None, True)
+ self.set_status("New article '%s' created in theme %s" % (newtext, sourcetheme))
+
+ elif type == "newtheme":
+ """ Creating a new theme """
+
+ if newtext.find("Create new theme") != -1:
+ # If the contents of the text box haven't changed, then we don't want to do anything
+ return
+
+ try:
+ # Create new topic in IO manager
+ IO_Manager().add_theme_to_library(newtext)
+
+ # Add new row for theme
+ themeiter = model.append(None, ["<b>%s</b>" % (newtext, ), self.themeicon, "theme", newtext, True])
+ model.append(themeiter, ["<i>Create new article</i>", self.newarticleicon, "newarticle", "aaaaaaaaaaaaaaaaaaaa", True])
+
+ except theme_exists_error:
+ # If the theme already exists, then we proceed to just highlight it.
+ self.highlight_theme(newtext)
+ return
+
+ # Highlight new theme
+ destpath = model.get_path(themeiter)
+ self.treeview.expand_to_path(destpath)
+ self.treeview.set_cursor(destpath, None, True)
+ self.set_status("New theme '%s' created" % (newtext, ))
+
+ def drag_begin_event(self, widget, context, data):
+ # This just aborts the drag if the user attempts to drag a theme.
+ model, sourceiter = widget.get_selection().get_selected()
+ type = model.get(sourceiter, 2)[0]
+ if type != "article" and type != "newarticle" and type != "wikiarticle":
+ context.drag_abort(int(time.time()))
+
+ def drag_drop_event(self, widget, context, x, y, time, data):
+ """
+ This method moves the source article to the topic that the user
+ has dragged it to.
+ """
+ # First, retrieve the initial selection
+ model, sourceiter = widget.get_selection().get_selected()
+ data = model.get(sourceiter, 0, 1, 2, 3, 4)
+ title = data[0]
+ type = data[2]
+
+ # The source theme is the label of the first node along the path to the current selection
+ sourcetheme = model.get(model.get_iter(model.get_path(sourceiter)[0]), 0)[0]
+ # Strip bold tags
+ sourcetheme = sourcetheme[3:len(sourcetheme)-4]
+
+ # Check the type, if the user didn't drag an article, we ignore
+ if type == "article":
+ # Work out the destination
+ destrow = widget.get_dest_row_at_pos(x, y)
+ destiter = model.get_iter((destrow[0][0], ))
+ destpath = (destrow[0][0], 0)
+ # Strip bold tags
+ desttheme = model.get(destiter, 0)[0]
+ desttheme = desttheme[3:len(desttheme)-4]
+
+ # If the theme already has an article with the name, we do nothing, and highlight the article
+ # in the destination theme
+ if IO_Manager().page_exists(title, desttheme):
+ self.highlight_article(desttheme, title)
+ return
+
+
+
+ # If the destination is the "Create new theme" bit, then
+ # we create a new theme and put the article in the new theme
+ if desttheme == "Wikipedia Articles":
+ return
+ elif desttheme == "Create new theme":
+ themes = IO_Manager().get_themes()
+ desttheme = "New Theme 1"
+ i = 1
+ while desttheme in themes:
+ i = i + 1
+ desttheme = "New Theme %d" % (i,)
+ IO_Manager().add_theme_to_library(desttheme)
+
+ # Add new row for theme
+ destiter = model.append(None, ["<b>%s</b>" % (desttheme, ), self.themeicon, "theme", desttheme, True])
+ model.append(destiter, ["<i>Create new article</i>", self.newarticleicon, "newarticle", "aaaaaaaaaaaaaaaaaaaa", True])
+
+ # Re-jig the rows on the visual side of things
+ destiter = self.treestore.insert(destiter, 0, data)
+ self.treestore.remove(sourceiter)
+ self.treeview.set_model(self.treestore)
+
+
+ # Re-jig the files in the filesystem
+ IO_Manager().move_page(sourcetheme, desttheme, title)
+
+ # Reset the topic in the source/working articles if appropriate
+ source = self.sourcetext.get_article()
+ edit = self.edittext.get_article()
+ if edit != None and edit.article_title == title and edit.article_theme == sourcetheme:
+ print "setting edit title"
+ edit.article_theme = desttheme
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%(desttheme, title))
+
+ # Highlight the result of the drag
+ destpath = model.get_path(destiter)
+ self.treeview.expand_to_path(destpath)
+ self.treeview.set_cursor(destpath, None, True)
+ self.set_status("Article %s moved from %s to %s" % (title, sourcetheme, desttheme))
+ elif type == "wikiarticle":
+ # Work out the destination
+ destrow = widget.get_dest_row_at_pos(x, y)
+ destiter = model.get_iter((destrow[0][0], ))
+ destpath = (destrow[0][0], 0)
+ # Strip bold tags
+ desttheme = model.get(destiter, 0)[0]
+ desttheme = desttheme[3:len(desttheme)-4]
+ # Strip the "from en.wikipedia.org" or equivalent name
+ i = title.find(" (from ")
+ newtitle = title[0:i]
+
+ i = 0
+ temptitle = newtitle
+ while IO_Manager().page_exists(temptitle, desttheme):
+ temptitle = "%s %d" % (newtitle, i)
+
+ newtitle = temptitle
+
+ # If the theme already has an article with the name, we do nothing, and highlight the article
+ # in the destination theme
+ if IO_Manager().page_exists(newtitle, desttheme):
+ self.highlight_article(desttheme, newtitle)
+ return
+
+
+
+ # If the destination is the "Create new theme" bit, then
+ # we create a new theme and put the article in the new theme
+ if desttheme == "Wikipedia Articles":
+ return
+ elif desttheme == "Create new theme":
+ themes = IO_Manager().get_themes()
+ desttheme = "New Theme 1"
+ i = 1
+ while desttheme in themes:
+ i = i + 1
+ desttheme = "New Theme %d" % (i,)
+ IO_Manager().add_theme_to_library(desttheme)
+
+ # Add new row for theme
+ destiter = model.append(None, ["<b>%s</b>" % (desttheme, ), self.themeicon, "theme", desttheme, True])
+ model.append(destiter, ["<i>Create new article</i>", self.newarticleicon, "newarticle", "aaaaaaaaaaaaaaaaaaaa", True])
+
+ # Re-jig the rows on the visual side of things
+ newdata = [newtitle, self.articleicon, "article", newtitle, True]
+ destiter = self.treestore.insert(destiter, 0, newdata)
+ self.treeview.set_model(self.treestore)
+
+ # Re-jig the files in the filesystem
+ IO_Manager().copy_page(title, sourcetheme, desttheme)
+ IO_Manager().rename_page(desttheme, title, newtitle)
+
+ # Reset the topic in the source/working articles if appropriate
+ source = self.sourcetext.get_article()
+ edit = self.edittext.get_article()
+
+ # Highlight the result of the drag
+ destpath = model.get_path(destiter)
+ self.treeview.expand_to_path(destpath)
+ self.treeview.set_cursor(destpath, None, True)
+
+ def drag_data_get_event(self, widget, context, selection_data, info, timestamp, data):
+ model, sourceiter = self.treeview.get_selection().get_selected()
+ type = model.get(sourceiter, 2)[0]
+ target = selection_data.target
+ if target == "sourcearticle":
+ if type == "wikiarticle":
+ atom = gtk.gdk.atom_intern("article")
+ title = self.get_current_article()
+ theme = self.get_current_theme()
+ string = cPickle.dumps([title, theme])
+ selection_data.set(atom, 8, string)
+ self.sourcepanelabel.set_markup("<span size='medium'><b>Wikipedia Article: </b> \n%s</span> "%(title, ))
+ elif target == "editarticle":
+ if type == "newarticle":
+ # If the type is "newarticle" then we create a new article
+ # and highlight it.
+
+ # Create and save the new article
+ theme = self.get_current_theme()
+ i = 0
+ title = "New Article"
+ while IO_Manager().page_exists(title, theme):
+ i = i + 1
+ title = "New Article %d" % (i, )
+ data = Article_Data(article_title = title, article_theme = theme)
+ article = Article(data)
+ IO_Manager().save_article(article)
+
+ # Add the row to the tree model
+ sourceiter = model.get_iter(model.get_path(sourceiter)[0])
+ destiter = model.append(sourceiter, [title, self.articleicon, "article", title, True])
+
+ # Highlight new row
+ destpath = model.get_path(destiter)
+ self.treeview.set_cursor(destpath, None, True)
+
+ # Set the selection data to the new article
+ atom = gtk.gdk.atom_intern("article")
+ string = cPickle.dumps([title, theme])
+ selection_data.set(atom, 8, string)
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%(theme, title))
+ elif type == "article":
+ # If type is article, set the selection data to the theme and articlename
+ atom = gtk.gdk.atom_intern("article")
+ title = self.get_current_article()
+ theme = self.get_current_theme()
+ string = cPickle.dumps([title, theme])
+ selection_data.set(atom, 8, string)
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%(theme, title))
+ elif type == "wikiarticle":
+ title = self.get_current_article()
+ theme = self.get_current_theme()
+ i = title.find(" (from ")
+ newtitle = title[0:i]
+
+ i = 0
+ temptitle = newtitle
+ while IO_Manager().page_exists(temptitle, "My Articles"):
+ i = i + 1
+ temptitle = "%s %d" % (newtitle, i)
+
+ newtitle = temptitle
+ article = Article()
+ article.article_title = newtitle
+ article.article_theme = "My Articles"
+ IO_Manager().save_article(article)
+
+
+ sourceiter = model.get_iter((1,))
+ destiter = model.append(sourceiter, [newtitle, self.articleicon, "article", newtitle, True])
+
+ destpath = self.treestore.get_path(destiter)
+ self.treeview.expand_to_path(destpath)
+ self.treeview.set_cursor(destpath, None, True)
+
+ self.sourcetext.set_article(IO_Manager().load_article(title, "Wikipedia Articles"))
+ self.sourcepanelabel.set_markup("<span size='medium'><b>Wikipedia Article: </b> \n%s</span> "%(title, ))
+
+
+ atom = gtk.gdk.atom_intern("article")
+ string = cPickle.dumps([newtitle, "My Articles"])
+ selection_data.set(atom, 8, string)
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%("My Articles", newtitle))
+
+ else:
+ # No data so nothing happens
+ pass
+
+
+ def commence_retrieval(self, widget, entry, statuslabel, wikimenu, wikidictionary):
+ title = entry.get_text()
+ wiki = wikidictionary[wikimenu.get_active_text()]
+ theme = "Wikipedia Articles"
+ if title == "" or title == None:
+ return
+ if IO_Manager().page_exists("%s (from %s)"%(title, wiki), theme):
+ statuslabel.set_label("%s already exists" % (title, ))
+ t = Timer(10, self.clear_label, [statuslabel])
+ t.start()
+ else:
+ t = Timer(0, self.download_and_add, [title, theme, wiki, statuslabel])
+ t.start()
+ #self.download(title, theme)
+
+
+ def download_and_add(self, title, theme, wiki, statuslabel):
+ #exceptions handled by IO_Manager
+ try:
+ statuslabel.set_label("Downloading %s..."%(title,))
+ IO_Manager().download_wiki_article(title=title, theme=theme, wiki = wiki, statuslabel=statuslabel)
+ except PageNotFoundError, e:
+ statuslabel.set_label("%s could not be found."%(title, ))
+ return
+ except:
+ statuslabel.set_label("Error downloading %s. Check your connection."%(title, ))
+ return
+
+ model = self.treeview.get_model()
+
+ wikipath = (0, )
+ wikiiter = model.get_iter(wikipath)
+ destiter = model.append(wikiiter, ["%s (from %s)"%(title, wiki), self.wikiarticleicon, "wikiarticle", "%s (from %s)"%(title, wiki), False])
+
+ destpath = model.get_path(destiter)
+ self.treeview.expand_to_path(destpath)
+
+ statuslabel.set_markup("%s successfully downloaded." % (title, ))
+ t = Timer(10, self.clear_label, [statuslabel])
+ t.start()
+
+ def clear_label(self, label):
+ label.set_markup("")
+
+
+ def set_source(self, article):
+ # Set the article in the source pane to 'article'
+ title = article.article_title
+ buf = article.getBuffer()
+ text = buf.get_slice(buf.get_start_iter(), buf.get_end_iter())
+ if article.article_title != None and text != "" and article.article_theme == "Wikipedia Articles":
+ self.sourcetext.set_article(article)
+ self.sourcepanelabel.set_markup("<b>Wikipedia Article: </b> \n%s "%(title, ))
+ else:
+ self.sourcetext.set_article(Article())
+ self.sourcetext.set_editable(False)
+ self.sourcetext.set_cursor_visible(False)
+
+ def get_source(self):
+ """
+ This returns the currently selected source article.
+ If the selected source article is from a different theme to the currently
+ selected edit article, then the article theme is changed. This only
+ a temporary change and since it is a source article it is read only
+ so it will never be saved.
+ New themes / articles are created and loaded in the event that
+ nothing is currently selected.
+ """
+ currentarticle = self.sourcetext.get_article()
+ if not currentarticle or not currentarticle.article_title or currentarticle.article_title == "":
+ article = Article()
+ else:
+ article = currentarticle
+ article.article_theme == "Wikipedia Articles"
+ return article
+
+
+ def set_working(self, article):
+ # Set the working article to 'article'
+ theme = article.article_theme
+ title = article.article_title
+ buf = article.getBuffer()
+ text = buf.get_slice(buf.get_start_iter(), buf.get_end_iter())
+ if text:
+ print "article has text"
+ if not theme:
+ theme = "My Articles"
+ if not title:
+ i = 0
+ title = "New Article"
+ while IO_Manager().page_exists(title, theme):
+ i = i + 1
+ title = "New Article %s" % (i, )
+ else:
+ if title and theme and "New Article" in title and not IO_Manager().page_exists(title, theme):
+ title == None
+ if theme and title and theme != "Wikipedia Articles":
+ if not self.article_exists_in_tree(theme, title):
+ self.add_article_to_tree(theme, title)
+ IO_Manager().save_article(article)
+ self.highlight_article(theme, title)
+ self.edittext.set_article(article)
+ self.editpanelabel.set_markup("<span size='medium'><b>Theme: </b> %s \n<b>Article to edit: </b> %s</span>"%(theme, title))
+
+ self.sourcetext.set_editable(False)
+ self.sourcetext.set_cursor_visible(False)
+
+ def get_working(self):
+ # Return the current working article, or create a new article in the current theme
+ # if there is no current working article.
+ currentarticle = self.edittext.get_article()
+ if currentarticle != None:
+ article = currentarticle
+ else:
+ article = Article()
+ title = article.article_title
+ theme = article.article_theme
+
+ if not theme or theme == "":
+ theme = "My Articles"
+ article.article_theme = theme
+
+ if not title or title == "":
+ sourcearticle = self.sourcetext.get_article()
+ if sourcearticle and sourcearticle.article_title:
+ sourcetitle = sourcearticle.article_title
+ else:
+ sourcetitle = ""
+ j = sourcetitle.find(" (from ")
+ if j != -1:
+ title = sourcetitle[0:j]
+ else:
+ title = "New Article"
+ articles = IO_Manager().get_pages_in_theme(theme)
+ i = 0
+ while title in articles:
+ i = i + 1
+ title = "New Article %d" % (i, )
+ print title
+ article.article_title = title
+
+ return article \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/Publish_View.py b/GUI_Components/Compound_Widgets/Publish_View.py
new file mode 100644
index 0000000..eb3272e
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Publish_View.py
@@ -0,0 +1,349 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+import cPickle
+import pango
+from Processing.IO_Manager import *
+from Processing.Article.Article import Article
+from Processing.Package_Creator import Package_Creator
+
+class Publish_View( gtk.VBox ):
+
+ def __init__(self):
+ gtk.VBox.__init__(self)
+ self.articlestocopy = []
+ self.themeselected = ''
+ running_on = platform.system()
+
+
+ paddingbox = gtk.HBox()
+ paddingbox.set_homogeneous(True)
+ self.pack_start(paddingbox)
+ self.child_set(paddingbox, "expand", True, "fill", True)
+ paddingbox.show()
+
+ pad1 = gtk.Label()
+ paddingbox.pack_start(pad1)
+ pad1.show()
+
+ self.themeviewcontainer = gtk.VBox()
+ self.themeviewcontainer.set_border_width(2)
+ paddingbox.pack_start(self.themeviewcontainer)
+ self.themeviewcontainer.show()
+
+ pad2 = gtk.Label()
+ paddingbox.pack_start(pad2)
+ pad2.show()
+
+ heading = gtk.Label("Click a theme:")
+ self.themeviewcontainer.pack_start(heading, False, False, 5)
+ heading.modify_font(pango.FontDescription('11'))
+ heading.show()
+
+ themeviewwindow = gtk.ScrolledWindow()
+ themeviewwindow.set_border_width(2)
+ themeviewwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.themeviewcontainer.pack_start(themeviewwindow)
+ themeviewwindow.show()
+
+ self.themeview = gtk.VBox()
+ themeviewwindow.add_with_viewport(self.themeview)
+ themeviewwindow.get_child().set_shadow_type(gtk.SHADOW_NONE)
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ themeviewwindow.get_child().modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#c0c0c0'))
+ self.themeview.show()
+
+ self.articleviewcontainer = gtk.VBox()
+ self.articleviewcontainer.set_border_width(2)
+ self.pack_start(self.articleviewcontainer)
+ self.articleviewcontainer.show()
+
+ box = gtk.HBox()
+ box.set_border_width(2)
+ self.articleviewcontainer.pack_start(box)
+ self.articleviewcontainer.child_set(box, "expand", False, "fill", False, "padding", 1)
+ box.show()
+
+ articleviewwindow = gtk.ScrolledWindow()
+ articleviewwindow.set_border_width(2)
+ articleviewwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.articleviewcontainer.pack_start(articleviewwindow)
+ articleviewwindow.show()
+
+ self.articleview = gtk.VBox()
+ articleviewwindow.add_with_viewport(self.articleview)
+ articleviewwindow.get_child().set_shadow_type(gtk.SHADOW_NONE)
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ articleviewwindow.get_child().modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#c0c0c0'))
+ self.articleview.show()
+
+ box2 = gtk.VBox()
+ box2.set_border_width(2)
+ self.articleviewcontainer.pack_start(box2)
+ box2.show()
+
+ box3 = gtk.HBox()
+ box2.pack_start(box3)
+ box3.show()
+
+ paddingbox = gtk.HBox()
+ paddingbox.set_homogeneous(True)
+ box3.pack_start(paddingbox)
+ paddingbox.show()
+
+ pad1 = gtk.Label()
+ paddingbox.pack_start(pad1)
+ pad1.show()
+
+
+
+ self.exportbutton = gtk.Button('Publish')
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ self.exportbutton.connect("clicked", self.sugarexport, self.articlestocopy)
+ else:
+ self.exportbutton.connect("clicked", self.export, self.articlestocopy)
+ self.articleviewcontainer.child_set(box2, "expand", False, "fill", False, "padding", 1)
+ paddingbox.pack_start(self.exportbutton)
+ self.exportbutton.show()
+
+ pad2 = gtk.Label()
+ paddingbox.pack_start(pad2)
+ pad2.show()
+
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ None
+ else:
+ self.combobox = gtk.combo_box_new_text()
+ self.combobox.append_text("Create Zip package")
+ self.combobox.append_text("Create bundle for Sugar")
+ self.combobox.set_active(0)
+ self.combobox.show()
+ box3.pack_start(self.combobox)
+
+ self.export_message = gtk.Label('Select the theme you want, choose the articles you wish to include in the package and click "Publish".')
+ self.export_message.show()
+ box2.pack_start(self.export_message)
+
+ self.populate_themes()
+
+ def populate_themes(self):
+ """
+ Clears the topics in the Topic View and re-populates by retrieving the topics from the library using IO_Manager
+ """
+
+ # Remove children currently in the topic view
+ for child in self.themeview.get_children():
+ self.themeview.remove(child)
+ child.destroy()
+ self.themebuttons = []
+
+ # Get topics from IO_Manager
+ themes = IO_Manager().get_themes()
+
+ button = gtk.RadioButton(None, "Hidden button!", None)
+ self.themeview.pack_start(button)
+ self.themeview.child_set(button, "expand", False, "fill", False)
+ button.connect("released", self.theme_selected, None)
+ self.themebuttons.append(button)
+ group = button
+# button.show()
+
+
+ # For each topic in the library, we create a button to represent the topic in the topic view,
+ # along with a button which will delete the topic when pressed. When the delete button is pressed,
+ # all the articles currently in the topic will be moved to the "Downloaded Articles" topic.
+ # We also set the button to be a drag destination for dragging in articles.
+ for theme in themes:
+ box = gtk.HBox()
+ self.themeview.pack_start(box)
+ self.themeview.child_set(box, "expand", False, "fill", False)
+ box.show()
+
+ button = gtk.RadioButton(group, theme, None)
+ box.pack_start(button)
+ button.set_mode(False)
+ button.set_relief(gtk.RELIEF_NONE)
+ button.set_property("can-focus", False)
+ box.child_set(button, "expand", True, "fill", True)
+ button.connect("released", self.theme_selected, None)
+ self.themebuttons.append(button)
+ group = button
+ button.show()
+
+ def populate_articles(self, theme):
+ """
+ Clears the articles in the list and re-populates by retrieving the articles in the theme selected from the library
+ using IO_Manager
+ @param theme: the name of the topic whose articles are to be displayed
+ """
+
+ # Remove everything in the article view
+ for child in self.articleview.get_children():
+ self.articleview.remove(child)
+ child.destroy()
+ self.articlebuttons = []
+
+ # Retrieve the articles for the specified topic, using IO_Manager
+ articles = IO_Manager().get_pages_in_theme(theme)
+ if articles == []:
+ return
+
+ length = len(articles)
+ wikiarticles = []
+ realarticles = []
+ for article in articles:
+ if "(from en.wikipedia.org)" in article or "(From En.Wikipedia.Org)" in article:
+ wikiarticles.append(article)
+ else:
+ realarticles.append(article)
+
+
+ group = None
+
+ # For each article, we package a button corresponding to the article, which when
+ # pressed is equivalent to the article being "selected". Also, a delete button, to
+ # delete the article, and then we also set it up as a drag source so that articles
+ # can be dragged between topics.
+ for article in realarticles:
+ title = article[0]
+ if title != "Blank Article":
+ box = gtk.HBox()
+ self.articleview.pack_start(box)
+ self.articleview.child_set(box, "expand", False, "fill", False)
+ box.show()
+
+ button = gtk.CheckButton(article)
+ button.set_mode(True)
+ button.connect("toggled", self.checked, button.get_children()[0].get_text())
+ button.set_active(True)
+ box.pack_start(button)
+ self.articlebuttons.append(button)
+ group = button
+ button.show()
+
+ for article in wikiarticles:
+ title = article[0]
+ if title != "Blank Article":
+ box = gtk.HBox()
+ self.articleview.pack_start(box)
+ self.articleview.child_set(box, "expand", False, "fill", False)
+ box.show()
+
+ button = gtk.CheckButton(article)
+ button.set_mode(True)
+ button.connect("toggled", self.checked, button.get_children()[0].get_text())
+ button.set_active(False)
+ box.pack_start(button)
+ self.articlebuttons.append(button)
+ group = button
+ button.show()
+
+ def checked(self, name, label):
+ """
+ Creates a list of articles to copy based on checked items
+ @param name: Name of the object which called the function
+ @param label: The name of the article to be added to the list
+ """
+ if name.get_active() == True:
+ self.articlestocopy.append(label)
+ else:
+ self.articlestocopy.remove(label)
+
+ def sugarexport(self, name, articlestocopy):
+ """
+ Creates a list of articles to copy based on checked items
+ @param name: Name of the object which called the function
+ @param articlestocopy: List of articles to copy
+ """
+ if not self.themeselected:
+ self.export_message.set_text('You need to choose a theme to package first.')
+ else:
+ Package_Creator(self.articlestocopy, self.themeselected, None, 'xol', self)
+
+ def export(self, name, articlestocopy):
+ """
+ Creates a list of articles to copy based on checked items
+ @param name: Name of the object which called the function
+ @param articlestocopy: List of articles to copy
+ """
+ #createPackage(self.articlestocopy, self.themeselected)
+ #self.notexported.hide()
+ #self.exported.show()
+
+ if not self.themeselected:
+ self.export_message.set_text('You need to choose a theme to bundle first.')
+ else:
+ combobox_choice = self.combobox.get_active_text()
+ if combobox_choice == 'Create bundle for Sugar':
+ package_type = 'xol'
+ elif combobox_choice == 'Create Zip package':
+ package_type = 'zip'
+ self.filechooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK))
+ self.filechooser.set_do_overwrite_confirmation(True)
+ self.filechooser.show()
+ response = self.filechooser.run()
+
+ if response == gtk.RESPONSE_OK:
+ filename = self.filechooser.get_filename()
+ filename = [filename]
+ filename.append(package_type)
+ full_filename = ".".join(filename)
+ Package_Creator(self.articlestocopy, self.themeselected, full_filename, package_type)
+ self.filechooser.destroy()
+ self.export_message.set_text('Bundle created. It has been saved to %s' % full_filename)
+ elif response == gtk.RESPONSE_CANCEL:
+ self.filechooser.destroy()
+
+ def destroy(self, widget):
+ gtk.main_quit()
+
+ def go_to_editpane(self, widget, event, data):
+ if event.type == gtk.gdk._2BUTTON_PRESS:
+ event = gtk.gdk.Event(gtk.gdk.KEY_PRESS)
+ event.keyval = gtk.keysyms.F2
+ event.time = 0 # assign current time
+ self.emit('key_press_event', event)
+
+ def highlight_theme(self, theme):
+ for button in self.themebuttons:
+ if button.get_label() == theme:
+ self.theme_selected(button, None)
+ button.clicked()
+
+ def highlight_article(self, title):
+ for button in self.articlebuttons:
+ if button.get_label() == title:
+ self.article_selected(button, None)
+ button.clicked()
+
+ def get_current_theme(self):
+ for button in self.themebuttons:
+ if button.get_active():
+ return button.get_label()
+
+ def get_current_theme_button(self):
+ for button in self.themebuttons:
+ if button.get_active():
+ return button
+
+ def set_source(self, article):
+ article = Article()
+ return article
+
+ def get_source(self):
+ article = Article()
+ return article
+
+ def set_working(self, article):
+ article = Article()
+ return article
+
+ def get_working(self):
+ article = Article()
+ return article
+
+ def theme_selected(self, button, data):
+ self.themeselected = button.get_label()
+ self.articlestocopy = []
+ self.populate_articles(self.themeselected) \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/Reading_View.py b/GUI_Components/Compound_Widgets/Reading_View.py
new file mode 100644
index 0000000..f044982
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/Reading_View.py
@@ -0,0 +1,74 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Compound_Widgets.Base_Widgets.Readonly_Textbox import Readonly_Textbox
+from Processing.IO_Manager import IO_Manager
+
+class Reading_View( gtk.VBox ):
+ """
+ Created by Jonathan Mace
+
+ This class wraps a Readonly_Textbox in a scrollable window, and adds
+ a combobox.
+ The combobox is populated, externally, with the names of
+ articles which can be selected.
+ If an article is selected in the combobox, the readonly_textbox will
+ be set to display the newly selected article.
+ The articles are loaded using IO_Manager
+ """
+
+ def __init__(self):
+ gtk.VBox.__init__(self)
+
+ self.articlemenu = gtk.combo_box_new_text()
+ self.articlemenu.connect("changed", self.source_selected, None)
+ self.pack_start(self.articlemenu, False, False, 1)
+ self.articlemenu.show()
+
+ self.articlewindow = gtk.ScrolledWindow()
+ self.articlewindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.pack_start(self.articlewindow)
+ self.articlewindow.show()
+
+ self.textbox = Readonly_Textbox()
+ self.articlewindow.add(self.textbox)
+ self.textbox.show()
+
+ def source_selected(self, combo, data):
+ title = combo.get_active_text()
+ if title == "Select a source article from this menu" or title == None:
+ return
+ if self.textbox.get_article() == None or self.textbox.get_article().article_title == title:
+ return
+ if combo.get_active != 0:
+ model = combo.get_model()
+ firstiter = model.get_iter_first()
+ firstvalue = model.get_value(firstiter, 0)
+ print firstvalue
+ if firstvalue == "Select a source article from this menu":
+ combo.remove_text(0)
+
+ if self.textbox.get_article() != None:
+ theme = "Wikipedia Articles"
+ try:
+ newarticle = IO_Manager().load_article(title, theme)
+ self.textbox.set_article(newarticle)
+ except Exception, e:
+ pass
+
+ def set_sentence_selection_mode(self):
+ self.textbox.set_mode(0)
+
+ def set_paragraph_selection_mode(self):
+ self.textbox.set_mode(1)
+
+ def set_section_selection_mode(self):
+ self.textbox.set_mode(2)
+
+ def set_full_edit_mode(self):
+ self.textbox.set_mode(3)
+
+ def clear_contents(self):
+ self.textbox.clear()
+ \ No newline at end of file
diff --git a/GUI_Components/Compound_Widgets/__init__.py b/GUI_Components/Compound_Widgets/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/GUI_Components/Compound_Widgets/__init__.py
diff --git a/GUI_Components/Edit_Pane.py b/GUI_Components/Edit_Pane.py
new file mode 100644
index 0000000..1b32268
--- /dev/null
+++ b/GUI_Components/Edit_Pane.py
@@ -0,0 +1,145 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Pane import Pane
+from GUI_Components.Compound_Widgets.Reading_View import Reading_View
+from GUI_Components.Compound_Widgets.Editing_View import Editing_View
+from GUI_Components.Compound_Widgets.Library_View import Library_View
+from Processing.Article.Article import Article
+from Processing.IO_Manager import IO_Manager
+
+class Edit_Pane(Pane):
+ """
+ Created by Jonathan Mace
+
+ See __init__.py for overview of panes.
+
+ The Edit Pane gives a side-by-side view of the source article and edit article
+ and allows users to drag text selections from the left hand (source) to the right
+ hand side (edited version).
+
+ The article displayed in the left hand side (source) can be changed by the
+ drop-down menu (implemented in Compound_Widgets.Reading_View)
+
+ The toolbar gives options to change the selection type.
+ """
+
+ def __init__(self):
+ Pane.__init__(self)
+ self.name = "Edit"
+
+ """
+ Create reading and editing panels
+ """
+ self.panel = gtk.HBox()
+ self.panel.set_homogeneous(True)
+ self.panel.show()
+
+ self.readarticle = Reading_View()
+ self.panel.pack_start(self.readarticle)
+ self.readarticle.show()
+
+ self.editarticle = Editing_View()
+ self.panel.pack_start(self.editarticle)
+ self.editarticle.show()
+
+ self.toolbar = gtk.Toolbar()
+
+ self.label = gtk.Label("Snap selection to: ")
+ self.label.show()
+
+ self.labelcontainer = gtk.ToolItem()
+ self.labelcontainer.add(self.label)
+ self.toolbar.insert(self.labelcontainer, -1)
+ self.labelcontainer.show()
+
+ """ Snap selection box """
+ self.combobox = gtk.combo_box_new_text()
+ self.combobox.append_text("Nothing")
+ self.combobox.append_text("Sentences")
+ self.combobox.append_text("Paragraphs")
+ self.combobox.append_text("Sections")
+ self.combobox.connect("changed", self.selection_mode_changed, None)
+ self.combobox.set_active(1)
+ self.combobox.show()
+
+ self.combocontainer = gtk.ToolItem()
+ self.combocontainer.add(self.combobox)
+ self.toolbar.insert(self.combocontainer, -1)
+ self.combocontainer.show()
+
+ """
+ When highlighting text, while editing, different selection snap methods
+ can be used (characters, sentences, paragraphs and sections). Change the selection
+ mode based on user request
+ """
+ def selection_mode_changed(self, widget, data):
+ current_selection = widget.get_active_text()
+ if current_selection == "Nothing":
+ self.readarticle.set_full_edit_mode()
+ self.editarticle.set_full_edit_mode()
+ elif current_selection == "Sentences":
+ self.readarticle.set_sentence_selection_mode()
+ self.editarticle.set_sentence_selection_mode()
+ elif current_selection == "Paragraphs":
+ self.readarticle.set_paragraph_selection_mode()
+ self.editarticle.set_paragraph_selection_mode()
+ elif current_selection == "Sections":
+ self.readarticle.set_section_selection_mode()
+ self.editarticle.set_section_selection_mode()
+ #print current_selection
+
+ def get_source_article(self):
+ return self.readarticle.textbox.get_article()
+
+ """
+ Grab source article from IO manager and set up as editing source.
+ """
+ def set_source_article(self, article):
+ # Populate the drop down menu with the articles in the current theme
+ article_theme = article.article_theme
+ article_title = article.article_title
+ if article_title == None:
+ article_title = ""
+ """ Grab media wiki pages from default wikipedia theme """
+ titles = IO_Manager().get_pages_in_theme("Wikipedia Articles")
+ self.readarticle.articlemenu.get_model().clear()
+ """ Check user has downloaded some source articles """
+ if titles != []:
+ self.readarticle.articlemenu.append_text("Select a source article from this menu")
+ if article_title == "":
+ buf = article.getBuffer()
+ start = buf.get_start_iter()
+ end = buf.get_end_iter()
+ buf.delete(start, end)
+ buf.insert(buf.get_start_iter(), "\nYou can choose a Wikipedia article to copy from by selecting it from the drop-down menu above.\n\n")
+ buf.insert(buf.get_end_iter(), "If you want to download more articles from Wikipedia, you can do this in the Library tab.")
+ else:
+ buf = article.getBuffer()
+ buf.insert(buf.get_start_iter(), "\nYou have not downloaded any articles from Wikipedia.\n\nYou can download new articles in the Library tab.")
+
+ i = 0
+ selectionindex = 0
+ for title in titles:
+ self.readarticle.articlemenu.append_text(title)
+ i = i + 1
+ if title == article_title:
+ selectionindex = i
+
+ self.readarticle.articlemenu.set_active(selectionindex)
+
+ # Set the read article as appropriate.
+ self.readarticle.textbox.set_article(article)
+
+
+ def get_working_article(self):
+ article = self.editarticle.textbox.get_article()
+ return article
+
+ def set_working_article(self, article):
+ self.editarticle.articletitle.set_markup("<span size='medium'><b>Theme:</b> %s \n<b>Article:</b> %s</span>"%(article.article_theme, article.article_title))
+ self.editarticle.textbox.set_article(article)
+ self.editarticle.article_theme = "Wikipedia Articles"
+
+ \ No newline at end of file
diff --git a/GUI_Components/Format_Pane.py b/GUI_Components/Format_Pane.py
new file mode 100644
index 0000000..5dff56d
--- /dev/null
+++ b/GUI_Components/Format_Pane.py
@@ -0,0 +1,98 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Pane import Pane
+from GUI_Components.Compound_Widgets.Editing_View import Editing_View
+
+class Format_Pane(Pane):
+ """
+ Created by Jonathan Mace
+
+ See __init__.py for overview of panes.
+
+ The Format Pane shows only the current edit article.
+ Users can apply formatting such as bold, underline etc.
+ Formatting has currently not been implemented. Dummy buttons are on the toolbar.
+ """
+
+ def __init__(self):
+ Pane.__init__(self)
+ self.name = "Format"
+
+ self.panel = Editing_View()
+ self.panel.show()
+
+ self.toolbar = gtk.Toolbar()
+
+ """
+ Snapping has been turned off in the Editable Textbox, so we no longer
+ make use of snapping. This has been left in case we turn it back on.
+
+ self.label = gtk.Label("Snap selection to: ")
+ self.label.show()
+
+ self.labelcontainer = gtk.ToolItem()
+ self.labelcontainer.add(self.label)
+ self.toolbar.insert(self.labelcontainer, -1)
+ self.labelcontainer.show()
+
+
+ self.combobox = gtk.combo_box_new_text()
+ self.combobox.append_text("Nothing")
+ self.combobox.append_text("Sentences")
+ self.combobox.append_text("Paragraphs")
+ self.combobox.append_text("Sections")
+ self.combobox.connect("changed", self.selection_mode_changed, None)
+ self.combobox.set_active(1)
+ self.combobox.show()
+
+
+ self.combocontainer = gtk.ToolItem()
+ self.combocontainer.add(self.combobox)
+ self.toolbar.insert(self.combocontainer, -1)
+ self.combocontainer.show()
+ """
+
+ self.boldbutton = gtk.ToolButton(gtk.STOCK_BOLD)
+ self.boldbutton.set_expand(False)
+ self.toolbar.insert(self.boldbutton, -1)
+ self.boldbutton.show()
+
+ self.italicbutton = gtk.ToolButton(gtk.STOCK_ITALIC)
+ self.italicbutton.set_expand(False)
+ self.toolbar.insert(self.italicbutton, -1)
+ self.italicbutton.show()
+
+ self.underlinebutton = gtk.ToolButton(gtk.STOCK_UNDERLINE)
+ self.underlinebutton.set_expand(False)
+ self.toolbar.insert(self.underlinebutton, -1)
+ self.underlinebutton.show()
+
+ """
+ User wants to change the default snap selection method
+ """
+ def selection_mode_changed(self, widget, data):
+ current_selection = widget.get_active_text()
+ if current_selection == "Nothing":
+ self.panel.set_full_edit_mode()
+ elif current_selection == "Sentences":
+ self.panel.set_sentence_selection_mode()
+ elif current_selection == "Paragraphs":
+ self.panel.set_paragraph_selection_mode()
+ elif current_selection == "Sections":
+ self.panel.set_section_selection_mode()
+
+ def get_source_article(self):
+ return self.source
+
+ def set_source_article(self, article):
+ self.source = article
+
+ def get_working_article(self):
+ article = self.panel.textbox.get_article()
+ return article
+
+ def set_working_article(self, article):
+ self.panel.articletitle.set_markup("<span size='medium'><b>Theme:</b> %s \n<b>Article:</b> %s</span>"%(article.article_theme, article.article_title))
+ self.panel.textbox.set_article(article) \ No newline at end of file
diff --git a/GUI_Components/Image_Pane.py b/GUI_Components/Image_Pane.py
new file mode 100644
index 0000000..8ebff64
--- /dev/null
+++ b/GUI_Components/Image_Pane.py
@@ -0,0 +1,125 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Pane import Pane
+from GUI_Components.Compound_Widgets.Editing_View import Editing_View
+from GUI_Components.Compound_Widgets.Gallery_View import Gallery_View
+from Processing.Article.Article import Article
+from Processing.IO_Manager import IO_Manager
+
+class Image_Pane(Pane):
+ """
+ Created by Christopher Leonard
+
+ See __init__.py for overview of panes.
+
+ The Image Pane gives a side-by-side view of the source article and edit article.
+ The left hand side shows images in the source article. These can be dragged into
+ the edit article.
+ """
+
+ def __init__(self):
+ Pane.__init__(self)
+ self.name = "Images"
+
+ self.panel = gtk.HBox()
+ self.panel.set_homogeneous(True)
+ self.panel.show()
+ self.gallery = Gallery_View()
+ self.panel.pack_start(self.gallery)
+ self.editarticle = Editing_View()
+ self.panel.pack_start(self.editarticle)
+ self.editarticle.show_all()
+
+ self.gallery._source_article = None
+
+ self.toolbar = gtk.Toolbar()
+ """
+ Snapping has been turned off in the Editable Textbox, so we no longer
+ make use of snapping. This has been left in case we turn it back on.
+
+
+ self.combobox = gtk.combo_box_new_text()
+ self.combobox.append_text("Nothing")
+ self.combobox.append_text("Sentences")
+ self.combobox.append_text("Paragraphs")
+ self.combobox.append_text("Sections")
+ self.combobox.connect("changed", self.selection_mode_changed, None)
+ self.combobox.set_active(1)
+ self.combobox.show()
+
+ self.combocontainer = gtk.ToolItem()
+ self.combocontainer.add(self.combobox)
+ self.toolbar.insert(self.combocontainer, -1)
+ self.combocontainer.show()
+ """
+
+ def selection_mode_changed(self, widget, data):
+ current_selection = widget.get_active_text()
+ if current_selection == "Nothing":
+ self.editarticle.set_full_edit_mode()
+ elif current_selection == "Sentences":
+ self.editarticle.set_sentence_selection_mode()
+ elif current_selection == "Paragraphs":
+ self.editarticle.set_paragraph_selection_mode()
+ elif current_selection == "Sections":
+ self.editarticle.set_section_selection_mode()
+
+
+ def set_source_article(self, source):
+ print "source received. title: %s, theme: %s" % (source.article_title, source.article_theme)
+ current = self.gallery._source_article
+ self.gallery._source_article = source
+ if source and source.article_title:
+ source.article_theme = "Wikipedia Articles"
+ if current:
+ if current.article_title == source.article_title and current.article_theme == source.article_theme:
+ print "same"
+ return
+ self.gallery.current_index = 0
+ if source.image_list != []:
+ print "setting images"
+ self.gallery.set_image_list(source.image_list)
+ self.gallery.get_first_item()
+
+ self.gallery.theme = "Wikipedia Articles"
+ self.gallery.source_article_id = source.source_article_id
+ print source.image_list
+ else:
+ self.gallery.imagenumberlabel.set_label("")
+ self.gallery.image.clear()
+ self.gallery.caption.set_text("This article does not have any images")
+ else:
+ self.gallery.imagenumberlabel.set_label("")
+ self.gallery.caption.set_text("Please select a Wikipedia article from the menu above")
+
+ def get_source_article(self):
+ return self.gallery._source_article
+
+ def get_working_article(self):
+ article = self.editarticle.textbox.get_article()
+ #data = article.getData()
+ return article
+
+ def set_working_article(self, article):
+ print "working received, title %s theme %s " % (article.article_title, article.article_theme)
+ self.editarticle.articletitle.set_markup("<span size='medium'><b>Theme:</b> %s \n<b>Article:</b> %s</span>"%(article.article_theme, article.article_title))
+ if article == None:
+ article = Article()
+ self.editarticle.textbox.set_article(article)
+ if article.article_theme == None:
+ article.article_theme = "My Articles"
+ theme_list = IO_Manager().get_pages_in_theme("Wikipedia Articles")
+ self.gallery.theme = "Wikipedia Articles"
+ count = -1
+ self.gallery.articlemenu.get_model().clear()
+
+ for item in theme_list:
+ count += 1
+ self.gallery.articlemenu.append_text(item)
+ if self.gallery._source_article != None and item == self.gallery._source_article.article_title:
+ self.gallery.articlemenu.set_active(count)
+
+
+ \ No newline at end of file
diff --git a/GUI_Components/Library_Pane.py b/GUI_Components/Library_Pane.py
new file mode 100644
index 0000000..10ec44a
--- /dev/null
+++ b/GUI_Components/Library_Pane.py
@@ -0,0 +1,106 @@
+# Copyright (C) IBM Corporation 2008
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Pane import Pane
+from GUI_Components.Compound_Widgets.Library_View import Library_View
+from GUI_Components.Compound_Widgets.Reading_View import Reading_View
+from Processing.IO_Manager import *
+
+class Library_Pane(Pane):
+ """
+ Created by Jonathan Mace
+
+ The Library Pane sets up a Library View and includes a toolbar which has
+ a text entry used for getting articles from Wikipedia.
+
+ The Library View contains the entire sum of articles downloaded from Wikipedia.
+ These articles can then be added to themes, editing and bundled into content packages
+ """
+
+ def __init__(self):
+ Pane.__init__(self)
+ self.wikis = {"English Wikipedia" : "en.wikipedia.org",
+ "Simple English Wikipedia" : "simple.wikipedia.org",
+ "German Wikipedia": "de.wikipedia.org"}
+ self.toolbar = gtk.Toolbar()
+
+
+ self.panel = gtk.HBox()
+ self.panel.set_homogeneous(True)
+ self.panel.show()
+
+ self.librarypanel = Library_View()
+ self.panel.pack_start(self.librarypanel)
+ self.librarypanel.show()
+
+ statuslabel = self.librarypanel.statusbar
+
+ # Set up the components of the toolbar
+ searchlabelitem = gtk.ToolItem()
+ self.toolbar.insert(searchlabelitem, -1)
+ searchlabelitem.show()
+
+ """
+ User search dialog
+ """
+ searchlabel = gtk.Label("Get article from ")
+ searchlabelitem.add(searchlabel)
+ searchlabel.show()
+
+ wikitoolitem = gtk.ToolItem()
+ self.toolbar.insert(wikitoolitem, -1)
+ wikitoolitem.show()
+
+ wikimenu = gtk.combo_box_new_text()
+ keys = self.wikis.keys()
+ keys.sort()
+ for wiki in keys:
+ wikimenu.append_text(wiki)
+ wikimenu.set_active(0)
+ wikitoolitem.add(wikimenu)
+ wikimenu.show()
+
+ searchentryitem = gtk.ToolItem()
+ self.toolbar.insert(searchentryitem, -1)
+ searchentryitem.show()
+
+ searchentry = gtk.Entry()
+ searchentry.set_text("Article name")
+ searchentry.connect("activate", self.click_search_button, None)
+ searchentryitem.add(searchentry)
+ searchentry.show()
+
+ self.searchbutton = gtk.ToolButton(gtk.STOCK_FIND)
+ self.searchbutton.connect("clicked", self.librarypanel.commence_retrieval, searchentry, statuslabel, wikimenu, self.wikis)
+ self.toolbar.insert(self.searchbutton, -1)
+ self.searchbutton.show()
+
+ # Add some blank space
+ blanklabel = gtk.Label(" ")
+ blanklabel.show()
+
+ blankitem = gtk.ToolItem()
+ blankitem.add(blanklabel)
+ self.toolbar.insert(blankitem, -1)
+ blankitem.show()
+
+
+ self.toolbar = self.toolbar
+ self.name = "Library"
+
+ def click_search_button(self, widget, data):
+ self.searchbutton.emit("clicked")
+
+ def get_source_article(self):
+ return self.librarypanel.get_source()
+
+ def set_source_article(self, article):
+ self.librarypanel.set_source(article)
+
+ def get_working_article(self):
+ return self.librarypanel.get_working()
+
+ def set_working_article(self, article):
+ self.librarypanel.set_working(article)
+ \ No newline at end of file
diff --git a/GUI_Components/Pane.py b/GUI_Components/Pane.py
new file mode 100644
index 0000000..ab1560c
--- /dev/null
+++ b/GUI_Components/Pane.py
@@ -0,0 +1,32 @@
+# Copyright (C) IBM Corporation 2008
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+class Pane:
+ """
+ An instance of the Pane class has a panel which is the main view,
+ a toolbar which interacts with the panel,
+ and methods for getting and setting the source and working articles.
+
+ """
+
+ def __init__(self):
+ # Pane instances have a panel, which is the main view of the pane
+ self.panel = gtk.Label()
+
+ # Pane instances have a toolbar
+ self.toolbar = gtk.Toolbar()
+
+ def get_working_article(self):
+ return self.working
+
+ def set_working_article(self, article):
+ self.working = article
+
+ def get_source_article(self):
+ return self.source
+
+ def set_source_article(self, article):
+ self.source = article \ No newline at end of file
diff --git a/GUI_Components/Publish_Pane.py b/GUI_Components/Publish_Pane.py
new file mode 100644
index 0000000..5d0a181
--- /dev/null
+++ b/GUI_Components/Publish_Pane.py
@@ -0,0 +1,42 @@
+# Copyright (C) IBM Corporation 2008
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+from GUI_Components.Pane import Pane
+from GUI_Components.Compound_Widgets.Publish_View import Publish_View
+from Processing.IO_Manager import *
+
+"""
+This pane is used when the user decides to package up articles in themes for distribution
+"""
+class Publish_Pane(Pane):
+
+ def __init__(self):
+ Pane.__init__(self)
+ self.toolbar = gtk.Toolbar()
+
+ self.name = "Publish"
+
+ self.panel = Publish_View()
+ self.panel.show()
+
+ self.toolbar = gtk.Toolbar()
+
+ def get_source_article(self):
+ return self.source
+
+ def set_source_article(self, article):
+ self.source = article
+
+ def get_working_article(self):
+ return self.working
+
+ def set_working_article(self, article):
+ theme = article.article_theme
+ title = article.article_title
+ if theme != None and title != None:
+ IO_Manager().save_article(article)
+ self.working = article
+ self.panel.populate_themes()
+ self.panel.export_message.set_text('Select the theme you want, choose the articles you wish to include in the package and click "Publish".') \ No newline at end of file
diff --git a/GUI_Components/__init__.py b/GUI_Components/__init__.py
new file mode 100644
index 0000000..d9b54cd
--- /dev/null
+++ b/GUI_Components/__init__.py
@@ -0,0 +1,21 @@
+# Copyright (C) IBM Corporation 2008
+"""
+Every class of type *_Pane has the following.
+Thank python for not having interfaces.
+
+pane.panel
+pane.toolbar
+
+These correspond to the main view and toolbar associated with this pane.
+
+set_source_article
+get_source_article
+set_working_article
+get_working_article
+
+The GUI passes the currently selected source and working articles between panes
+when panes are switched. The pane will always be given an article using
+set_source_article before the get_source_article method is called. Thus it is
+feasible to just save the article argument and return it in the get method.
+
+""" \ No newline at end of file
diff --git a/INFO.txt b/INFO.txt
new file mode 100644
index 0000000..aedfd0b
--- /dev/null
+++ b/INFO.txt
@@ -0,0 +1,21 @@
+InfoSlicer downloads articles from Wikipedia so that you can create
+new documents by dragging and dropping content from the Wikipedia
+articles. You can then publish the articles as a mini website.
+
+Copyright (C) IBM Corporation 2008
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Contact: Laura Cowen (laura_cowen@uk.ibm.com) \ No newline at end of file
diff --git a/Infoslicer_GUI.py b/Infoslicer_GUI.py
new file mode 100644
index 0000000..7d2ab48
--- /dev/null
+++ b/Infoslicer_GUI.py
@@ -0,0 +1,435 @@
+# Copyright (C) IBM Corporation 2008
+
+import pygtk
+import sys
+pygtk.require('2.0')
+import gtk
+import time
+import platform
+from GUI_Components.Edit_Pane import Edit_Pane
+from GUI_Components.Format_Pane import Format_Pane
+from GUI_Components.Library_Pane import Library_Pane
+from GUI_Components.Image_Pane import Image_Pane
+from GUI_Components.Publish_Pane import Publish_Pane
+from Processing.Article.Article import Article
+from Processing.IO_Manager import IO_Manager
+
+class Infoslicer_GUI:
+ """
+ Created by Jonathan Mace
+
+ This is an abstract class. Whichever platform decides to run the app
+ must created a subclass of this class.
+
+ """
+
+ def __init__(self):
+ print "InfoSlicer version 0.1, Copyright (C) 2008 IBM Corporation\
+ \nInfoSlicer comes with ABSOLUTELY NO WARRANTY; for details run the program with the `-warranty' argument.\
+ \nThis is free software, and you are welcome to redistribute it under certain conditions; type `-conditions' for details."
+ self._parse_args()
+ self.__set_up_GUI()
+
+ def _parse_args(self):
+ for arg in sys.argv:
+ if arg == "-warranty" or arg == "-conditions":
+ print "GNU GENERAL PUBLIC LICENSE \
+ \nTERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION \
+ \n \
+0. This License applies to any program or other work which contains\n\
+a notice placed by the copyright holder saying it may be distributed\n\
+under the terms of this General Public License. The \"Program\", below,\n\
+refers to any such program or work, and a \"work based on the Program\"\n\
+means either the Program or any derivative work under copyright law:\n\
+that is to say, a work containing the Program or a portion of it,\n\
+either verbatim or with modifications and/or translated into another\n\
+language. (Hereinafter, translation is included without limitation in\n\
+the term \"modification\".) Each licensee is addressed as \"you\".\n\
+Activities other than copying, distribution and modification are not\n\
+covered by this License; they are outside its scope. The act of\n\
+running the Program is not restricted, and the output from the Program\n\
+is covered only if its contents constitute a work based on the\n\
+Program (independent of having been made by running the Program).\n\
+Whether that is true depends on what the Program does.\n\
+\n\
+ 1. You may copy and distribute verbatim copies of the Program's\n\
+source code as you receive it, in any medium, provided that you\n\
+conspicuously and appropriately publish on each copy an appropriate\n\
+copyright notice and disclaimer of warranty; keep intact all the\n\
+notices that refer to this License and to the absence of any warranty;\n\
+and give any other recipients of the Program a copy of this License\n\
+along with the Program.\n\
+\n\
+You may charge a fee for the physical act of transferring a copy, and\n\
+you may at your option offer warranty protection in exchange for a fee.\n\
+\n\
+ 2. You may modify your copy or copies of the Program or any portion\n\
+of it, thus forming a work based on the Program, and copy and\n\
+distribute such modifications or work under the terms of Section 1\n\
+above, provided that you also meet all of these conditions:\n\
+\n\
+ a) You must cause the modified files to carry prominent notices\n\
+ stating that you changed the files and the date of any change.\n\
+\n\
+ b) You must cause any work that you distribute or publish, that in\n\
+ whole or in part contains or is derived from the Program or any\n\
+ part thereof, to be licensed as a whole at no charge to all third\n\
+ parties under the terms of this License.\n\
+\n\
+ c) If the modified program normally reads commands interactively\n\
+ when run, you must cause it, when started running for such\n\
+ interactive use in the most ordinary way, to print or display an\n\
+ announcement including an appropriate copyright notice and a\n\
+ notice that there is no warranty (or else, saying that you provide\n\
+ a warranty) and that users may redistribute the program under\n\
+ these conditions, and telling the user how to view a copy of this\n\
+ License. (Exception: if the Program itself is interactive but\n\
+ does not normally print such an announcement, your work based on\n\
+ the Program is not required to print an announcement.)\n\
+\n\
+These requirements apply to the modified work as a whole. If\n\
+identifiable sections of that work are not derived from the Program,\n\
+and can be reasonably considered independent and separate works in\n\
+themselves, then this License, and its terms, do not apply to those\n\
+sections when you distribute them as separate works. But when you\n\
+distribute the same sections as part of a whole which is a work based\n\
+on the Program, the distribution of the whole must be on the terms of\n\
+this License, whose permissions for other licensees extend to the\n\
+entire whole, and thus to each and every part regardless of who wrote it.\n\
+\n\
+Thus, it is not the intent of this section to claim rights or contest\n\
+your rights to work written entirely by you; rather, the intent is to\n\
+exercise the right to control the distribution of derivative or\n\
+collective works based on the Program.\n\
+\n\
+In addition, mere aggregation of another work not based on the Program\n\
+with the Program (or with a work based on the Program) on a volume of\n\
+a storage or distribution medium does not bring the other work under\n\
+the scope of this License.\n\
+\n\
+ 3. You may copy and distribute the Program (or a work based on it,\n\
+under Section 2) in object code or executable form under the terms of\n\
+Sections 1 and 2 above provided that you also do one of the following:\n\
+\n\
+ a) Accompany it with the complete corresponding machine-readable\n\
+ source code, which must be distributed under the terms of Sections\n\
+ 1 and 2 above on a medium customarily used for software interchange; or,\n\
+\n\
+ b) Accompany it with a written offer, valid for at least three\n\
+ years, to give any third party, for a charge no more than your\n\
+ cost of physically performing source distribution, a complete\n\
+ machine-readable copy of the corresponding source code, to be\n\
+ distributed under the terms of Sections 1 and 2 above on a medium\n\
+ customarily used for software interchange; or,\n\
+\n\
+ c) Accompany it with the information you received as to the offer\n\
+ to distribute corresponding source code. (This alternative is\n\
+ allowed only for noncommercial distribution and only if you\n\
+ received the program in object code or executable form with such\n\
+ an offer, in accord with Subsection b above.)\n\
+\n\
+The source code for a work means the preferred form of the work for\n\
+making modifications to it. For an executable work, complete source\n\
+code means all the source code for all modules it contains, plus any\n\
+associated interface definition files, plus the scripts used to\n\
+control compilation and installation of the executable. However, as a\n\
+special exception, the source code distributed need not include\n\
+anything that is normally distributed (in either source or binary\n\
+form) with the major components (compiler, kernel, and so on) of the\n\
+operating system on which the executable runs, unless that component\n\
+itself accompanies the executable.\n\
+\n\
+If distribution of executable or object code is made by offering\n\
+access to copy from a designated place, then offering equivalent\n\
+access to copy the source code from the same place counts as\n\
+distribution of the source code, even though third parties are not\n\
+compelled to copy the source along with the object code.\n\
+\n\
+ 4. You may not copy, modify, sublicense, or distribute the Program\n\
+except as expressly provided under this License. Any attempt\n\
+otherwise to copy, modify, sublicense or distribute the Program is\n\
+void, and will automatically terminate your rights under this License.\n\
+However, parties who have received copies, or rights, from you under\n\
+this License will not have their licenses terminated so long as such\n\
+parties remain in full compliance.\n\
+\n\
+ 5. You are not required to accept this License, since you have not\n\
+signed it. However, nothing else grants you permission to modify or\n\
+distribute the Program or its derivative works. These actions are\n\
+prohibited by law if you do not accept this License. Therefore, by\n\
+modifying or distributing the Program (or any work based on the\n\
+Program), you indicate your acceptance of this License to do so, and\n\
+all its terms and conditions for copying, distributing or modifying\n\
+the Program or works based on it.\n\
+\n\
+ 6. Each time you redistribute the Program (or any work based on the\n\
+Program), the recipient automatically receives a license from the\n\
+original licensor to copy, distribute or modify the Program subject to\n\
+these terms and conditions. You may not impose any further\n\
+restrictions on the recipients' exercise of the rights granted herein.\n\
+You are not responsible for enforcing compliance by third parties to\n\
+this License.\n\
+\n\
+ 7. If, as a consequence of a court judgment or allegation of patent\n\
+infringement or for any other reason (not limited to patent issues),\n\
+conditions are imposed on you (whether by court order, agreement or\n\
+otherwise) that contradict the conditions of this License, they do not\n\
+excuse you from the conditions of this License. If you cannot\n\
+distribute so as to satisfy simultaneously your obligations under this\n\
+License and any other pertinent obligations, then as a consequence you\n\
+may not distribute the Program at all. For example, if a patent\n\
+license would not permit royalty-free redistribution of the Program by\n\
+all those who receive copies directly or indirectly through you, then\n\
+the only way you could satisfy both it and this License would be to\n\
+refrain entirely from distribution of the Program.\n\
+\n\
+If any portion of this section is held invalid or unenforceable under\n\
+any particular circumstance, the balance of the section is intended to\n\
+apply and the section as a whole is intended to apply in other\n\
+circumstances.\n\
+\n\
+It is not the purpose of this section to induce you to infringe any\n\
+patents or other property right claims or to contest validity of any\n\
+such claims; this section has the sole purpose of protecting the\n\
+integrity of the free software distribution system, which is\n\
+implemented by public license practices. Many people have made\n\
+generous contributions to the wide range of software distributed\n\
+through that system in reliance on consistent application of that\n\
+system; it is up to the author/donor to decide if he or she is willing\n\
+to distribute software through any other system and a licensee cannot\n\
+impose that choice.\n\
+\n\
+This section is intended to make thoroughly clear what is believed to\n\
+be a consequence of the rest of this License.\n\
+\n\
+ 8. If the distribution and/or use of the Program is restricted in\n\
+certain countries either by patents or by copyrighted interfaces, the\n\
+original copyright holder who places the Program under this License\n\
+may add an explicit geographical distribution limitation excluding\n\
+those countries, so that distribution is permitted only in or among\n\
+countries not thus excluded. In such case, this License incorporates\n\
+the limitation as if written in the body of this License.\n\
+\n\
+ 9. The Free Software Foundation may publish revised and/or new versions\n\
+of the General Public License from time to time. Such new versions will\n\
+be similar in spirit to the present version, but may differ in detail to\n\
+address new problems or concerns.\n\
+\n\
+Each version is given a distinguishing version number. If the Program\n\
+specifies a version number of this License which applies to it and \"any\n\
+later version\", you have the option of following the terms and conditions\n\
+either of that version or of any later version published by the Free\n\
+Software Foundation. If the Program does not specify a version number of\n\
+this License, you may choose any version ever published by the Free Software\n\
+Foundation.\n\
+\n\
+ 10. If you wish to incorporate parts of the Program into other free\n\
+programs whose distribution conditions are different, write to the author\n\
+to ask for permission. For software which is copyrighted by the Free\n\
+Software Foundation, write to the Free Software Foundation; we sometimes\n\
+make exceptions for this. Our decision will be guided by the two goals\n\
+of preserving the free status of all derivatives of our free software and\n\
+of promoting the sharing and reuse of software generally.\n\
+\n\
+ NO WARRANTY\n\
+\n\
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
+PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
+REPAIR OR CORRECTION.\n\
+\n\
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
+POSSIBILITY OF SUCH DAMAGES.\n\
+\n\
+ END OF TERMS AND CONDITIONS\n\
+\n\
+ How to Apply These Terms to Your New Programs\n\
+\n\
+ If you develop a new program, and you want it to be of the greatest\n\
+possible use to the public, the best way to achieve this is to make it\n\
+free software which everyone can redistribute and change under these terms.\n\
+\n\
+ To do so, attach the following notices to the program. It is safest\n\
+to attach them to the start of each source file to most effectively\n\
+convey the exclusion of warranty; and each file should have at least\n\
+the \"copyright\" line and a pointer to where the full notice is found.\n\
+\n\
+ <one line to give the program's name and a brief idea of what it does.>\n\
+ Copyright (C) <year> <name of author>\n\
+\n\
+ This program is free software; you can redistribute it and/or modify\n\
+ it under the terms of the GNU General Public License as published by\n\
+ the Free Software Foundation; either version 2 of the License, or\n\
+ (at your option) any later version.\n\
+\n\
+ This program is distributed in the hope that it will be useful,\n\
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
+ GNU General Public License for more details.\n\
+\n\
+ You should have received a copy of the GNU General Public License along\n\
+ with this program; if not, write to the Free Software Foundation, Inc.,\n\
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\
+\n\
+Also add information on how to contact you by electronic and paper mail.\n\
+\n\
+If the program is interactive, make it output a short notice like this\n\
+when it starts in an interactive mode:\n\
+\n\
+ Gnomovision version 69, Copyright (C) year name of author\n\
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n\
+ This is free software, and you are welcome to redistribute it\n\
+ under certain conditions; type `show c' for details.\n\
+\n\
+The hypothetical commands `show w' and `show c' should show the appropriate\n\
+parts of the General Public License. Of course, the commands you use may\n\
+be called something other than `show w' and `show c'; they could even be\n\
+mouse-clicks or menu items--whatever suits your program.\n\
+\n\
+You should also get your employer (if you work as a programmer) or your\n\
+school, if any, to sign a \"copyright disclaimer\" for the program, if\n\
+necessary. Here is a sample; alter the names:\n\
+\n\
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n\
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\
+\n\
+ <signature of Ty Coon>, 1 April 1989\n\
+ Ty Coon, President of Vice\n\
+\n\
+This General Public License does not permit incorporating your program into\n\
+proprietary programs. If your program is a subroutine library, you may\n\
+consider it more useful to permit linking proprietary applications with the\n\
+library. If this is what you want to do, use the GNU Lesser General\n\
+Public License instead of this License.\n\
+"
+ return
+
+ def setpanel(self, panel):
+ """
+ This method sets the main display to the panel specified.
+ """
+ pass
+
+ def clearpanel(self):
+ """
+ This method clears the main display (if setpanel does not clear it before setting)
+ """
+ pass
+
+ def settoolbars(self):
+ """
+ This method sets the toolbars. Toolbars are stored in self.toolbars and the
+ corresponding toolbar names are stored in self.toolbarnames
+ """
+ pass
+
+ def switch_page(self, page_num):
+ """
+ This method sets the current page to page_num when called.
+ """
+ pass
+
+ """
+ Change tab shown and available to the user.
+ """
+ def mode_switched(self, mode):
+ # Mode is the index of the tab that has been switched to
+ if self.currentindex != mode:
+ pane = self.panes[mode]
+ if self.currentpane != None:
+ self.source = self.currentpane.get_source_article()
+ self.working = self.currentpane.get_working_article()
+ pane.set_source_article(self.source)
+ pane.set_working_article(self.working)
+ self.clearpanel()
+ self.setpanel(pane.panel)
+ self.currentpane = pane
+ self.currentindex = mode
+
+ def __set_up_GUI(self):
+ # Set up dummy library if appropriate
+ running_on = platform.system()
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ themes = IO_Manager().get_themes()
+ if themes == []:
+ IO_Manager().install_library()
+ # Instantiate the panels to be displayed by the GUI
+ self.library = Library_Pane()
+ self.panes = [self.library,
+ Edit_Pane(),
+ Format_Pane(),
+ Image_Pane(),
+ Publish_Pane()]
+
+ # Create the original and edited articles to be used by the GUI
+
+ self.source = Article()
+ self.working = Article()
+ ignore = False
+
+
+ themes = IO_Manager().get_themes()
+ if "Wikipedia Articles" in themes:
+ i = themes.index("Wikipedia Articles")
+ del themes[i]
+
+ wikiarticles = IO_Manager().get_pages_in_theme("Wikipedia Articles")
+ for theme in themes:
+ articles = IO_Manager().get_pages_in_theme(theme)
+ for article in articles:
+ if ignore == True:
+ break
+ for wikiarticle in wikiarticles:
+ if article in wikiarticle:
+ self.source = IO_Manager().load_article(wikiarticle, "Wikipedia Articles")
+ self.working = IO_Manager().load_article(article, theme)
+ print "loading source %s from %s" % (wikiarticle, "Wikipedia Articles")
+ print "loading edit %s from %s" % (article, theme)
+ ignore = True
+
+ self.currentpane = None
+
+ self.library.panel.connect("key-press-event", self.go_arrange_mode, None)
+
+ # Add toolbars and panels but keep hidden]
+ toolbars = [pane.toolbar for pane in self.panes]
+ toolbarnames = [pane.name for pane in self.panes]
+ self.settoolbars(toolbars, toolbarnames)
+
+ # Set the current index to -1 so that the first pane will always be shown
+ self.currentindex = -1
+
+ """
+ Respond to function key presses
+ """
+ def go_arrange_mode(self, widget, event, data):
+ key = event.keyval
+ if key == gtk.keysyms.F1:
+ print "f1"
+ self.switch_page(0)
+ if key == gtk.keysyms.F2:
+ print "f2"
+ self.switch_page(1)
+ if key == gtk.keysyms.F3:
+ print "f3"
+ self.switch_page(2)
+
+ """
+ Save and quit current article
+ """
+ def do_quit_event(self):
+ print "quitting"
+ article = self.currentpane.get_working_article()
+ IO_Manager().save_article(article)
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..63e41a4
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. \ No newline at end of file
diff --git a/Processing/Article/Article.py b/Processing/Article/Article.py
new file mode 100644
index 0000000..6580a45
--- /dev/null
+++ b/Processing/Article/Article.py
@@ -0,0 +1,770 @@
+# Copyright (C) IBM Corporation 2008
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+from random import Random
+from Article_Data import *
+from Processing.Article.Section import *
+
+arrow_xpm = [
+"15 11 4 1",
+" c None s None",
+". c black",
+"r c #800000",
+"R c #FF0000",
+" .. ",
+" .... ",
+" .rr.. ",
+" .....rRr.. ",
+"..rrrrrRRr.. ",
+"..rRRRRRRRr.. ",
+"..rRRRRRRr.. ",
+" .....rRr.. ",
+" .rr.. ",
+" .... ",
+" .. ",
+]
+
+
+
+class Article:
+ """
+ Created by Jonathan Mace
+
+ The Article class maintains a concrete representation of the article, in the form of a gtk.TextBuffer
+
+ Positions within the text are represented by gtk.TextIter
+
+ The class contains methods for inserting and deleting new sentences, paragraphs and sections.
+
+ The class also has methods for finding the most appropriate insertion point for new sections.
+
+ The class maintains the section-based structure of the article.
+
+ At any point, the article_data class corresponding to the current state of the article can be retrieved
+ """
+
+
+ """
+ Construct article to be displayed in the GUI from the data object passed in
+ """
+ def __init__(self, article_data = Article_Data()):
+ """
+ Create default text buffer and set to empty
+ """
+ self.__buf = gtk.TextBuffer()
+ self.__buf.set_text("")
+ insertionpoint = self.__buf.get_end_iter()
+ insertionmark = self.__buf.create_mark(None, insertionpoint, False)
+
+ """
+ Set the attributes such as title, theme, id etc. as specified in the article_data parameter
+ """
+ self.id = article_data.id
+ self.article_title = article_data.article_title
+ self.article_theme = article_data.article_theme
+ self.source_article_id = article_data.source_article_id
+ self.image_list = article_data.get_image_list()
+
+ """
+ The article is currently blank, so there are no sections
+ """
+ self.__sections = []
+
+
+ """
+ Create new sections based on the section data in article_data
+ At this level, nothing is actually inserted into the textbuffer.
+ The text insertion occurs at the sentence level.
+ The sentences are created within the initialisation of the Section object.
+ """
+ sections_data = article_data.sections_data
+ for section_data in sections_data:
+ insertioniter = self.__buf.get_iter_at_mark(insertionmark)
+ self.__sections.append(Section(section_data, self.__buf, insertioniter))
+
+ self.__buf.delete_mark(insertionmark)
+
+ """
+ We also append dummy sections, containing nothing, at the start and end of the article.
+ """
+ startdummy = dummySection(self.__buf, self.__buf.get_start_iter(), True)
+ enddummy = dummySection(self.__buf, self.__buf.get_end_iter(), False)
+ self.__sections = [startdummy] + self.__sections + [enddummy]
+
+ self.markmark = None
+
+ def printsections(self):
+ """
+ This was a method to help debugging. It prints the contents of the article
+ as represented by the article/section/paragraph/sentence data structures
+ as opposed to just the contents of the text buffer. If for some reason,
+ some elements are not consistent with where they begin and end, then this
+ would become apparent by using this method
+ """
+ pass
+ """
+ for section in self.__sections:
+ print "section start: %s, end: %s, id: %s" % (section.getStart().get_offset(), section.getEnd().get_offset(), section.id)
+ paragraphs = section.paragraphs
+ for paragraph in paragraphs:
+ print " paragraph start: %s, end %s, id: %s" % (paragraph.getStart().get_offset(), paragraph.getEnd().get_offset(), paragraph.id)
+ sentences = paragraph.sentences
+ for sentence in sentences:
+ print " sentence start: %s, end: %s, id: %s, text: %s" % (sentence.getStart().get_offset(), sentence.getEnd().get_offset(), sentence.id, sentence.getText())
+ """
+
+ def getData(self):
+ """
+ Returns the article_data object corresponding to the current state of the article.
+ """
+ self.checkIntegrity()
+ id = self.id
+ source_article_id = self.source_article_id
+ article_title = self.article_title
+ article_theme = self.article_theme
+ image_list = self.image_list
+ sections_data = []
+ for section in self.__sections[1:len(self.__sections)-1]:
+ sections_data.append(section.getData())
+
+ data = Article_Data(id, source_article_id, article_title, article_theme, sections_data, image_list)
+
+ return data
+
+ def checkIntegrity(self):
+ """
+ When a user freely edits the text of an article, they can perform actions such as completely deleting a sentence,
+ or concatenating two sections, etc.
+ This method reparses the structure of the article.
+ """
+ i = 0
+ sections = []
+ while i < len(self.__sections)-1:
+ section = self.__sections[i]
+ nextsection = self.__sections[i+1]
+
+ if section.getStart().compare(nextsection.getStart()) == -1:
+ text = self.__buf.get_slice(section.getStart(), nextsection.getStart())
+ if len(text) > 2 and text[-2] != "\n":
+ nextsection.paragraphs = section.paragraphs + nextsection.paragraphs
+ else:
+ sections.extend(section.checkIntegrity(nextsection.getStart()))
+ else:
+ section.remove()
+ del self.__sections[i]
+ i = i - 1
+
+ i = i + 1
+
+ section = self.__sections[-1]
+ if section.getStart().compare(self.__buf.get_end_iter()) == -1:
+ if len(text) > 2 and text[-2] != "\n":
+ pars = section.paragraphs
+ par = pars[-1]
+ if text[-1] != "\n":
+ data = Sentence_Data(-1, -1, -1, -1, -1, "\n", None)
+ pars[-2].sentences.append(Sentence(data, self.__buf, par.getStart()))
+ data = Paragraph_Data(-1, -1, -1, -1, [])
+ pars.append(Paragraph(data, self.__buf, par.getEnd()))
+ elif par.getText() == "\n":
+ data = Sentence_Data(-1, -1, -1, -1, -1, "\n", None)
+ pars[-2].sentences.append(Sentence(data, self.__buf, par.getStart()))
+ else:
+ data = Paragraph_Data(-1, -1, -1, -1, [])
+ pars.append(Paragraph(data, self.__buf, par.getEnd()))
+ sections.extend(section.checkIntegrity(self.__buf.get_end_iter()))
+
+ self.__sections = sections
+
+
+ startdummy = dummySection(self.__buf, self.__buf.get_start_iter(), True)
+ enddummy = dummySection(self.__buf, self.__buf.get_end_iter(), False)
+ self.__sections = [startdummy] + self.__sections + [enddummy]
+ self.generateIds()
+
+ i = 1
+ while i < len(self.__sections)-1:
+ j = 0
+ section = self.__sections[i]
+ while j < len(section.paragraphs) - 1:
+ k = 0
+ paragraph = section.paragraphs[j]
+ while k < len(paragraph.sentences) - 1:
+ sentence = paragraph.sentences[k]
+ if sentence.getStart().compare(sentence.getEnd()) > -1:
+ sentence.remove()
+ del paragraph.sentences[k]
+ k = k - 1
+ k = k+1
+ if paragraph.sentences == []:
+ del section.paragraphs[j]
+ j = j - 1
+ j = j+1
+ if section.paragraphs == []:
+ del self.__sections[i]
+ i = i - 1
+ i = i+1
+
+
+ def generateIds(self):
+ for section in self.__sections[1:len(self.__sections)-1]:
+ section.generateIds()
+
+
+ def insert(self, objects, lociter):
+ """
+ This method is used for inserting new sentences, paragraphs and/or sections into the article.
+
+ The position specified by lociter can be any location within the textbuffer.
+
+ Objects is a list of Section objects to be inserted into the article.
+
+ The list can also be prepended and appended by Paragraph objects, and then again by Sentence objects.
+
+ So, objects will be a list of the form:
+ [sentence objects] ++ [paragraph objects] ++ [section objects] ++ [paragraph objects] ++ [sentence objects]
+
+ If sections are being inserted, then the first sentence array and paragraph array will each contain a dummy object.
+
+ Likewise, if only paragraphs are being inserted, then the first sentence array will contain a dummy object.
+
+ The section objects array and the second paragraph and sentence arrays, can all be empty.
+ """
+
+ sectionnumber = self.__get_exact_section(lociter)
+ if sectionnumber == len(self.__sections)-1:
+ self.__pad()
+ lociter = self.__sections[-2].getStart()
+ section = self.__sections[sectionnumber]
+
+ extra = 0
+ secstart = section.getStart()
+ secend = section.getEnd()
+
+ if secstart.compare(lociter)==0 and (secend.get_offset() - secstart.get_offset()) < 4:
+ extra = 3
+ elif secend.get_offset() - lociter.get_offset() < 4:
+ extra = 3
+
+ paragraph = section.getParagraph(lociter)
+ if paragraph == section.getParagraphs()[-1]:
+ section.pad()
+ paragraph = section.getParagraphs()[-2]
+ lociter = paragraph.getStart()
+
+ insertioniter = paragraph.getBestSentence(lociter).getStart()
+ insertionmark = self.__buf.create_mark(None, insertioniter, False)
+
+ self.insertionsectionstart = self.__buf.create_mark(None, section.getStart(), True)
+ self.insertionsectionend = self.__buf.create_mark(None, section.getEnd(), False)
+ self.insertionstartdist = insertioniter.get_offset() - section.getStart().get_offset()
+ self.insertionenddist = section.getEnd().get_offset() - insertioniter.get_offset() - extra
+
+ split = False
+
+
+ if objects != []:
+ object = objects[0]
+
+ if object.type == "section":
+ del objects[0]
+ dummyparagraphdata = Paragraph_Data(id = -1, sentences_data = [])
+ objects = object.paragraphs_data + [dummyparagraphdata] + objects
+ object = objects[0]
+ if object.type == "paragraph":
+ del objects[0]
+ dummysentencedata = Sentence_Data(id = -1, text = "")
+ objects = object.sentences_data + [dummysentencedata] + objects
+ object = objects[0]
+
+
+
+ while objects != [] and (object.type == "sentence" or object.type == "picture"):
+ # it text = "" then we have reached the end of the first list and must break. We don't insert
+ # this blank sentence, it is just a placeholder
+ if object.text != "":
+ insertioniter = self.__buf.get_iter_at_mark(insertionmark)
+ paragraph.insertSentence(object, insertioniter)
+ else:
+ split = True
+ del objects[0]
+ break
+
+ del objects[0]
+ if objects != []:
+ object = objects[0]
+
+ splititer = self.__buf.get_iter_at_mark(insertionmark)
+ splitmark = self.__buf.create_mark(None, splititer, True)
+
+ if objects != []:
+ object = objects[-1]
+ while objects != [] and (object.type == "sentence" or object.type == "picture"):
+ # Now, we actually add the ending sentences first, then split the paragraph at the splitmark
+ # which was created between the two while loops
+ insertioniter = self.__buf.get_iter_at_mark(splitmark)
+ paragraph.insertSentence(object, insertioniter)
+
+ del objects[-1]
+ if objects != []:
+ object = objects[-1]
+
+
+ paragraph.clean()
+ section.clean()
+
+
+ # Now we simply split the paragraph at the splitmark, then call the insertparagraphs method with
+ # the remaining contents of objects
+ if split:
+ splititer = self.__buf.get_iter_at_mark(splitmark)
+ offset = splititer.get_offset()
+ section.splitParagraph(splititer)
+ insertioniter = self.__buf.get_iter_at_offset(offset)
+ if objects != []:
+ self.__insertParagraphs(objects, insertioniter)
+
+ self.highlightDragResult()
+
+ def __insertParagraphs(self, objects, lociter):
+ """
+ This method is the same as the above insert method, except that sentence objects are not included.
+
+ So, objects is a list which can take the form:
+ [ paragraph objects ] ++ [ section objects ] ++ [ paragraph objects ]
+
+ And again, if the objects list does contain sections, then the first paragraph array will end with a dummy paragraph object.
+ """
+
+
+ sectionnumber = self.__get_exact_section(lociter)
+ section = self.__sections[sectionnumber]
+ lociter = self.__buf.get_iter_at_offset(lociter.get_offset()+1)
+
+ insertioniter = section.getBestParagraph(lociter).getStart()
+ insertionmark = self.__buf.create_mark(None, insertioniter, False)
+
+ split = False
+
+ object = objects[0]
+
+ if object.type == "section":
+ del objects[0]
+ blankparagraph = Paragraph_Data(id = -1, sentences_data = [])
+ objects = object.paragraphs_data + [blankparagraph] + objects
+ object = objects[0]
+
+ while objects != [] and object.type == "paragraph":
+ # First, deal with the paragraph triples. We insert these into the current section.
+ # Then when we run out of paragraph triples, we split the section.
+
+ # if sentences = [] then we have reached the end of the first list and must break.
+ # We do not insert this empty paragraph, it is just a placeholder.
+ if object.sentences_data != []:
+ insertioniter = self.__buf.get_iter_at_mark(insertionmark)
+ section.insertParagraph(object, insertioniter)
+ else:
+ split = True
+ del objects[0]
+ break
+
+ del objects[0]
+ if objects != []:
+ object = objects[0]
+
+ splititer = self.__buf.get_iter_at_mark(insertionmark)
+ splitmark = self.__buf.create_mark(None, splititer, True)
+
+ if objects != []:
+ object = objects[-1]
+ while objects != [] and object.type == "paragraph":
+ # Now, we actually add the ending paragraphs, then split the section at the splitmark
+ # which was created between the two while loops
+ insertioniter = self.__buf.get_iter_at_mark(splitmark)
+ section.insertParagraph(object, insertioniter)
+
+ del objects[-1]
+ if objects != []:
+ object = objects[-1]
+
+
+ # Now we simply split the section at the splitmark, then call the insertsections method with
+ # the remaining contents of objects
+ if split:
+ splititer = self.__buf.get_iter_at_mark(splitmark)
+ offset = splititer.get_offset()
+ splititer = self.getParagraph(splititer).getStart()
+ self.__splitSection(splititer)
+ insertioniter = self.__buf.get_iter_at_offset(offset)
+ if objects != []:
+ self.__insertSections(objects, insertioniter)
+
+ def __insertSections(self, objects, lociter):
+ """
+ objects is a list of section objects, and lociter is a location in the textbuffer
+
+ We find the closest section gap to the lociter specified, and then insert the sections at this point.
+ """
+ insertioniter = self.getBestSection(lociter).getStart()
+ insertionmark = self.__buf.create_mark(None, insertioniter, False)
+ for object in objects:
+ insertioniter = self.__buf.get_iter_at_mark(insertionmark)
+ self.insertSection(object, insertioniter)
+
+ def getSelection(self):
+ """
+ If the user has highlighted some text, this method returns the sentence/paragraph/section based
+ representation of the selection
+ """
+ buf = self.__buf
+ bounds = buf.get_selection_bounds()
+ if bounds[0].compare(bounds[1]) == 1:
+ start = bounds[1]
+ end = bounds[0]
+ else:
+ start = bounds[0]
+ end = bounds[1]
+ data = self.getRange(start, end)
+ return data
+
+
+ def getRange(self, startiter, enditer):
+ """
+ This method returns the section, paragraph and sentence objects between startiter and enditer
+ """
+
+ startindex = self.__get_exact_section(startiter)
+ endindex = self.__get_exact_section(enditer)
+ if startindex == endindex:
+ data = self.__sections[startindex].getDataRange(startiter, enditer)
+ else:
+ startdata = []
+ startsection = self.__sections[startindex]
+ if startiter.compare(startsection.getStart()) == 0:
+ startdata.append(self.__sections[startindex].getData())
+ else:
+ startdata.extend(startsection.getDataRange(startiter, startsection.getEnd()))
+ startdata.append(Paragraph_Data(id = -1, sentences_data = []))
+
+ middledata = []
+ for section in self.__sections[startindex+1:endindex]:
+ middledata.append(section.getData())
+
+ enddata = []
+ if endindex != len(self.__sections):
+ endsection = self.__sections[endindex]
+ enddata.extend(endsection.getDataRange(endsection.getStart(), enditer))
+
+ data = startdata + middledata + enddata
+
+ return data
+
+
+
+ def getBuffer(self):
+ """
+ This method simply returns the gtk.TextBuffer being maintained by this instance of the Article class.
+ """
+ return self.__buf
+
+
+ def insertSection(self, section_data, lociter):
+ """
+ This method inserts a single section into the article.
+
+ The section is represented by section_data, and the insertion point is specified by lociter
+
+ The section is inserted into the closest gap to lociter.
+ """
+ insertionindex = self.__get_best_section(lociter)
+ if insertionindex == 0: insertionindex = insertionindex + 1
+ insertioniter = self.__sections[insertionindex].getStart()
+ section = Section(section_data, self.__buf, insertioniter)
+ self.__sections.insert(insertionindex, section)
+
+ def deleteSection(self, lociter):
+ """
+ This method deletes the section which contains lociter.
+ """
+ deletionindex = self.__get_exact_section(lociter)
+ if deletionindex != len(self.__sections) - 1:
+ section = self.__sections[deletionindex]
+ section.delete()
+ del self.__sections[deletionindex]
+
+ def removeSection(self, lociter):
+ """
+ This method has the same effect as deleteSection
+ """
+ removalindex = self.__get_exact_section(lociter)
+ section = self.__sections[removalindex]
+ section.delete()
+ del self.__sections[removalindex]
+
+ def deleteSelection(self, startiter, enditer):
+ """
+ This method deletes all sentence, paragraph and data objects from startiter to enditer.
+ """
+ startindex = self.__get_exact_section(startiter)
+ endindex = self.__get_exact_section(enditer)
+ if endindex == len(self.__sections) - 1:
+ endindex = endindex - 1
+ if startindex == endindex:
+ empty = self.__sections[startindex].deleteSelection(startiter, enditer)
+ if empty:
+ self.__sections[startindex].delete()
+ del self.__sections[startindex]
+ elif startindex < endindex:
+ startmark = self.__buf.create_mark(None, startiter, True)
+ endmark = self.__buf.create_mark(None, enditer, True)
+
+ endsection = self.__sections[endindex]
+ empty = endsection.deleteSelection(endsection.getStart(), self.__buf.get_iter_at_mark(endmark))
+ if empty:
+ self.__sections[endindex].delete()
+ del self.__sections[endindex]
+ self.__buf.delete_mark(endmark)
+
+ for i in range(startindex + 1, endindex):
+ self.__sections[startindex + 1].delete()
+ del self.__sections[startindex + 1]
+
+ startsection = self.__sections[startindex]
+ empty = startsection.deleteSelection(self.__buf.get_iter_at_mark(startmark), startsection.getEnd())
+ if empty:
+ self.__sections[startindex].delete()
+ del self.__sections[startindex]
+ self.__buf.delete_mark(startmark)
+
+ def rememberSelection(self):
+ """
+ This method is uses to remember a specific selection.
+
+ It is currently used to remember what text the user is dragging around within the article.
+ """
+ bounds = self.__buf.get_selection_bounds()
+ self.selectionlength = bounds[1].get_offset() - bounds[0].get_offset()
+ self.selectionstartoffset = bounds[0].get_offset()
+ self.selectionstartmark = self.__buf.create_mark(None, bounds[0], True)
+ self.selectionendmark = self.__buf.create_mark(None, bounds[1], True)
+
+ def deleteDragSelection(self):
+ """
+ This method deletes the selection which was saved by the rememberSelection method
+
+ This occurs when a user is rearranging text within the same article; the text will be inserted somewhere,
+ and then the old text will be deleted.
+ """
+
+ deletestart = self.__buf.get_iter_at_mark(self.selectionstartmark)
+ deletestartoffset = deletestart.get_offset()
+
+ if deletestart.get_offset() != self.selectionstartoffset:
+ deleteend = self.__buf.get_iter_at_mark(self.selectionendmark)
+ deletestart = self.__buf.get_iter_at_offset(deleteend.get_offset() - self.selectionlength)
+ else:
+ deleteend = self.__buf.get_iter_at_offset(deletestartoffset + self.selectionlength)
+
+ self.deleteSelection(deletestart, deleteend)
+ self.__buf.delete_mark(self.selectionstartmark)
+ self.__buf.delete_mark(self.selectionendmark)
+
+ def highlightDragResult(self):
+ """
+ When stuff is inserted into the article, the method that deals with the insertion keeps track of where it was inserted.
+
+ This method highlights the inserted text.
+ """
+ startoffset = self.__buf.get_iter_at_mark(self.insertionsectionstart).get_offset() + self.insertionstartdist
+ endoffset = self.__buf.get_iter_at_mark(self.insertionsectionend).get_offset() - self.insertionenddist
+ startiter = self.__buf.get_iter_at_offset(startoffset)
+ enditer = self.__buf.get_iter_at_offset(endoffset)
+ self.__buf.select_range(startiter, enditer)
+ self.__buf.delete_mark(self.insertionsectionstart)
+ self.__buf.delete_mark(self.insertionsectionend)
+
+ def __get_best_section(self, lociter):
+ """
+ Given any position within the buffer, this method determines where the closest section gap is.
+
+ It then returns the index of the section, within the self.__sections list, of the preceeding section.
+ """
+ sectionindex = self.__get_exact_section(lociter)
+ section = self.__sections[sectionindex]
+ left = section.getStart().get_offset()
+ middle = lociter.get_offset()
+ right = section.getEnd().get_offset()
+ leftdist = middle - left
+ rightdist = right - middle
+
+ if (sectionindex < len(self.__sections)) and (leftdist > rightdist):
+ sectionindex = sectionindex +1
+ return sectionindex
+
+ def __get_exact_section(self, lociter):
+ """
+ Given any position within the buffer, this method determines which section the lociter is inside.
+ """
+ i = 0
+ for i in range(len(self.__sections)-1):
+ start = self.__sections[i+1].getStart()
+ if lociter.compare(start) == -1:
+ return i
+ return len(self.__sections)-1
+
+ def highlight(self, startiter, enditer):
+ """
+ This method highlights the text between startiter and enditer.
+ """
+ comparison = startiter.compare(enditer)
+ if comparison == 0:
+ sentence = self.getSentence(startiter)
+ self.__buf.select_range(sentence.getStart(), sentence.getEnd())
+ else:
+ self.__buf.select_range(startiter, enditer)
+
+ def mark(self, lociter):
+ """
+ This method puts an arrow image at the start of sentence that lociter is within.
+ """
+ sentence = self.getSentence(lociter)
+ self.clearArrow()
+ lociter = sentence.getStart()
+ self.markmark = self.__buf.create_mark(None, lociter, True)
+ self.__buf.insert(lociter, " ")
+ lociter = self.__buf.get_iter_at_mark(self.markmark)
+ arrow = gtk.gdk.pixbuf_new_from_xpm_data(arrow_xpm)
+ self.__buf.insert_pixbuf(lociter, arrow)
+
+
+ def clearArrow(self):
+ """
+ This method removes the arrow image, if there is one.
+ """
+ if self.markmark == None:
+ return
+ markiter = self.__buf.get_iter_at_mark(self.markmark)
+ markenditer = self.__buf.get_iter_at_offset(markiter.get_offset()+2)
+ self.__buf.delete(markiter, markenditer)
+ self.__buf.delete_mark(self.markmark)
+ self.markmark = None
+
+ def getBestSentence(self, lociter):
+ """
+ This method finds the closest sentence gap to lociter.
+
+ It then returns the sentence object of the first sentence to occur after the gap.
+ """
+ paragraph = self.getParagraph(lociter)
+ sentence = paragraph.getBestSentence(lociter)
+ return sentence
+
+ def getBestParagraph(self, lociter):
+ """
+ This method finds the closest paragraph gap to lociter.
+
+ It then returns the paragraph object of the first paragraph to occur after the gap.
+ """
+ section = self.getSection(lociter)
+ paragraph = section.getBestParagraph(lociter)
+ return paragraph
+
+ def getBestSection(self, lociter):
+ """
+ This method finds the closest section gap to lociter.
+
+ It then returns the section object of the first section to occur after the gap.
+ """
+ sectionindex = self.__get_best_section(lociter)
+ if sectionindex == len(self.__sections):
+ return self.__sections[-1]
+ else:
+ return self.__sections[sectionindex]
+
+ def getSentence(self, lociter):
+ """
+ This method returns the sentence which contains lociter.
+ """
+ paragraph = self.getParagraph(lociter)
+ sentence = paragraph.getSentence(lociter)
+ return sentence
+
+ def getParagraph(self, lociter):
+ """
+ This method returns the paragraph which contains lociter.
+ """
+ section = self.getSection(lociter)
+ paragraph = section.getParagraph(lociter)
+ return paragraph
+
+ def getSection(self, lociter):
+ """
+ This method returns the section which contains lociter.
+ """
+ sectionindex = self.__get_exact_section(lociter)
+ section = self.__sections[sectionindex]
+ return section
+
+ def __splitSection(self, lociter):
+ """
+ This method finds the section which contains lociter.
+
+ It then finds the closest paragraph gap to lociter.
+
+ The section is then split into two sections, one containing all the paragraphs before the gap,
+ the other containing all the paragraphs after the gap.
+ """
+ sectionindex = self.__get_exact_section(lociter)
+ section = self.__sections[sectionindex]
+
+ source_article_id = section.source_article_id
+ source_section_id = section.source_section_id
+
+ offset = lociter.get_offset()
+ section.splitParagraph(lociter)
+ lociter = self.__buf.get_iter_at_offset(offset)
+
+
+ firstdata = section.getDataRange(section.getStart(), lociter)
+ seconddata = section.getDataRange(lociter, section.getEnd())
+ mark = self.__buf.create_mark(None, lociter, False)
+ if firstdata != [] and seconddata != []:
+ self.deleteSection(lociter)
+
+ insertioniter = self.__buf.get_iter_at_mark(mark)
+ sectiondata = Section_Data(None, source_article_id, source_section_id, firstdata)
+ section = Section(sectiondata, self.__buf, insertioniter)
+ self.__sections.insert(sectionindex, section)
+
+ insertioniter = self.__buf.get_iter_at_mark(mark)
+ sectiondata = Section_Data(None, source_article_id, source_section_id, seconddata)
+ section = Section(sectiondata, self.__buf, insertioniter)
+ self.__sections.insert(sectionindex+1, section)
+
+ def __pad(self):
+ """
+ This method adds an empty section at the end of the article.
+
+ It is currently used in preparation for something being inserted at the end of the article.
+ """
+ sentencedata = Sentence_Data(id = -1, text = " ")
+ paragraphdata = Paragraph_Data(id = -1, sentences_data = [sentencedata])
+ sectiondata = Section_Data(id = -1, paragraphs_data = [paragraphdata])
+ insertioniter = self.__sections[-1].getStart()
+ section = Section(sectiondata, self.__buf, insertioniter)
+ self.__sections.insert(-1, section)
+
+ def __clean(self):
+ """
+ Removes the effects of one use of pad.
+
+ If pad has been called more than once, then clean must be called the same number of times.
+ """
+ if len(self.__sections) > 2:
+ section = self.__sections[-2]
+ sectionisempty = section.clean()
+ if sectionisempty:
+ del self.__sections[-2]
+
diff --git a/Processing/Article/Article_Data.py b/Processing/Article/Article_Data.py
new file mode 100644
index 0000000..2be0a75
--- /dev/null
+++ b/Processing/Article/Article_Data.py
@@ -0,0 +1,78 @@
+# Copyright (C) IBM Corporation 2008
+
+import random
+
+"""
+Created by Jonathan Mace
+
+Each class in this file represents the data associated with an element of an article.
+
+These are the data objects which are passed around to and from the Article class.
+"""
+
+class Sentence_Data:
+
+ def __init__(self, id = None, source_article_id = -1, source_section_id = -1, source_paragraph_id = -1, source_sentence_id = -1, text = "", formatting = None):
+ if id == None:
+ self.id = random.randint(100, 100000)
+ else:
+ self.id = id
+ self.source_article_id = source_article_id
+ self.source_section_id = source_section_id
+ self.source_paragraph_id = source_paragraph_id
+ self.source_sentence_id = source_sentence_id
+ self.text = text
+ self.formatting = formatting
+ self.type = "sentence"
+
+class Picture_Data:
+
+ def __init__(self, source_article_id = -1, text = None):
+ self.source_article_id = source_article_id
+ self.id = 0
+ self.text = text
+ self.type = "picture"
+
+
+class Paragraph_Data:
+
+ def __init__(self, id = None, source_article_id = -1, source_section_id = -1, source_paragraph_id = -1, sentences_data = []):
+ if id == None:
+ self.id = random.randint(100, 100000)
+ else:
+ self.id = id
+ self.source_article_id = source_article_id
+ self.source_section_id = source_section_id
+ self.source_paragraph_id = source_paragraph_id
+ self.sentences_data = sentences_data
+ self.type = "paragraph"
+
+class Section_Data:
+
+ def __init__(self, id = None, source_article_id = -1, source_section_id = -1, paragraphs_data = []):
+ if id == None:
+ self.id = random.randint(100, 100000)
+ else:
+ self.id = id
+ self.source_article_id = source_article_id
+ self.source_section_id = source_section_id
+ self.paragraphs_data = paragraphs_data
+ self.type = "section"
+
+class Article_Data:
+
+ def __init__(self, id = None, source_article_id = -1, article_title = None, article_theme = None, sections_data = [], image_list=[]):
+ if id == None:
+ self.id = random.randint(100, 100000)
+ else:
+ self.id = id
+ self.source_article_id = source_article_id
+ self.article_title = article_title
+ self.article_theme = article_theme
+ self.sections_data = sections_data
+ self.type = "article"
+ self.image_list = image_list
+
+ def get_image_list(self):
+ return self.image_list
+ \ No newline at end of file
diff --git a/Processing/Article/Paragraph.py b/Processing/Article/Paragraph.py
new file mode 100644
index 0000000..ac578b5
--- /dev/null
+++ b/Processing/Article/Paragraph.py
@@ -0,0 +1,254 @@
+# Copyright (C) IBM Corporation 2008
+
+from Processing.Article.Sentence import *
+
+"""
+Created by Jonathan Mace
+
+The classes here each correspond to a sentence in the given text buffer.
+
+You should not instantiate these classes directly.
+
+Use the "level above" class or the Article class to apply changes to the textbuffer
+or structure of the article.
+
+"""
+
+"""
+a Paragraph instance contains a list of sentences. It has methods for inserting,
+deleting and rearranging sentences within itself, as well as other housekeeping
+functions.
+
+"""
+
+class RawParagraph:
+
+ def __init__(self, id, source_article_id, source_section_id, source_paragraph_id, sentences, buf):
+ self.id = id
+ self.source_article_id = source_article_id
+ self.source_section_id = source_section_id
+ self.source_paragraph_id = source_paragraph_id
+ self.sentences = sentences
+ self.buf = buf
+
+ def insertSentence(self, sentence_data, lociter):
+ insertionindex = self.__get_best_sentence(lociter)
+ insertioniter = self.sentences[insertionindex].getStart()
+ if sentence_data.type == "sentence":
+ sentence = Sentence(sentence_data, self.buf, insertioniter)
+ elif sentence_data.type == "picture":
+ sentence = Picture(sentence_data, self.buf, insertioniter)
+ else:
+ print "WARNING, WEIRD SENTENCES: %s" % (sentence_data.type, )
+ self.sentences.insert(insertionindex, sentence)
+
+ def deleteSentence(self, lociter):
+ deletionindex = self.__get_exact_sentence(lociter)
+ if deletionindex != len(self.sentences) - 1:
+ sentence = self.sentences[deletionindex]
+ sentence.delete()
+ del self.sentences[deletionindex]
+ if len(self.sentences) == 1:
+ return True
+ else:
+ return False
+
+ def removeSentence(self, lociter):
+ removalindex = self.__get_exact_sentence(lociter)
+ if removalindex != len(self.sentences) - 1:
+ sentence = self.sentences[removalindex]
+ sentence.remove()
+ del self.sentences[removalindex]
+ if len(self.sentences) == 1:
+ return True
+ else:
+ return False
+
+ def delete(self):
+ for sentence in self.sentences:
+ sentence.delete()
+
+ def deleteSelection(self, startiter, enditer):
+ startindex = self.__get_exact_sentence(startiter)
+ endindex = self.__get_exact_sentence(enditer)
+ for i in range(startindex, endindex):
+ self.sentences[startindex].delete()
+ del self.sentences[startindex]
+ if len(self.sentences) == 1:
+ return True
+ else:
+ return False
+
+ def remove(self):
+ for sentence in self.sentences:
+ sentence.remove()
+
+ def getSentence(self, lociter):
+ sentenceindex = self.__get_exact_sentence(lociter)
+ return self.sentences[sentenceindex]
+
+ def getBestSentence(self, lociter):
+ sentenceindex = self.__get_best_sentence(lociter)
+ if sentenceindex == len(self.sentences):
+ return self.sentences[-1]
+ else:
+ return self.sentences[sentenceindex]
+
+ def getStart(self):
+ return self.sentences[0].getStart()
+
+
+ def getEnd(self):
+ return self.sentences[-1].getEnd()
+
+ def __get_best_sentence(self, lociter):
+ sentenceindex = self.__get_exact_sentence(lociter)
+ sentence = self.sentences[sentenceindex]
+ left = sentence.getStart().get_offset()
+ middle = lociter.get_offset()
+ right = sentence.getEnd().get_offset()
+ leftdist = middle - left
+ rightdist = right - middle
+
+ if (sentenceindex < len(self.sentences)) and (leftdist > rightdist):
+ sentenceindex = sentenceindex +1
+ return sentenceindex
+
+
+ def __get_exact_sentence(self, lociter):
+ i = 0
+ for i in range(len(self.sentences)-1):
+ start = self.sentences[i+1].getStart()
+ if lociter.compare(start) == -1:
+ return i
+ return len(self.sentences) - 1
+
+ def getId(self):
+ return self.id
+
+ def getData(self):
+ id = self.id
+ source_article_id = self.source_article_id
+ source_section_id = self.source_section_id
+ source_paragraph_id = self.source_paragraph_id
+ sentences_data = []
+ for sentence in self.sentences[0:len(self.sentences)-1]:
+ sentences_data.append(sentence.getData())
+
+ data = Paragraph_Data(id, source_article_id, source_section_id, source_paragraph_id, sentences_data)
+ return data
+
+ def getDataRange(self, startiter, enditer):
+ startindex = self.__get_exact_sentence(startiter)
+ endindex = self.__get_exact_sentence(enditer)
+ sentences_data = []
+ for sentence in self.sentences[startindex:endindex]:
+ sentences_data.append(sentence.getData())
+ return sentences_data
+
+ def mark(self):
+ markiter = self.getStart()
+ self.markmark = self.buf.create_mark(None, markiter, True)
+ arrow = gtk.gdk.pixbuf_new_from_xpm_data(arrow_xpm)
+ self.buf.insert_pixbuf(markiter, arrow)
+
+ def unmark(self):
+ markiter = self.buf.get_iter_at_mark(self.markmark)
+ markenditer = self.buf.get_iter_at_offset(markiter.get_offset()+1)
+ self.buf.delete(markiter, markenditer)
+ self.buf.delete_mark(self.markmark)
+
+ def getSentences(self):
+ return self.sentences
+
+ def getText(self):
+ return self.buf.get_slice(self.getStart(), self.getEnd())
+
+ def clean(self):
+ if len(self.sentences) > 1:
+ sentence = self.sentences[-2]
+ if sentence.getId() == -1:
+ sentence.delete()
+ del self.sentences[-2]
+ if len(self.sentences) == 1:
+ return True
+ else:
+ return False
+ return True
+
+ def checkIntegrity(self, nextiter):
+
+ i = 0
+ sentences = []
+ while i < len(self.sentences) - 1:
+ sentence = self.sentences[i]
+ nextsentence = self.sentences[i+1]
+
+ if sentence.getStart().compare(nextsentence.getStart()) == -1:
+ sentences.extend(sentence.checkIntegrity(nextsentence.getStart()))
+ else:
+ sentence.remove()
+ del self.sentences[i]
+ i = i - 1
+
+ i = i + 1
+
+ sentence = self.sentences[-1]
+ if sentence.getStart().compare(nextiter) == -1:
+ sentences.extend(sentence.checkIntegrity(nextiter))
+
+ paragraphs = []
+ paragraphstart = 0
+ for i in range(len(sentences)-1):
+ if sentences[i].getText() == "\n":
+ paragraphs.append(RawParagraph(self.id, self.source_article_id, self.source_section_id, self.source_paragraph_id, sentences[paragraphstart:i+1], self.buf))
+ paragraphstart = i + 1
+ paragraphs.append(RawParagraph(self.id, self.source_article_id, self.source_section_id, self.source_paragraph_id, sentences[paragraphstart:len(sentences)], self.buf))
+
+ return paragraphs
+
+ def generateIds(self):
+ if self.id == None or self.id == -1:
+ self.id = random.randint(100, 100000)
+ for sentence in self.sentences[0:len(self.sentences)-1]:
+ sentence.generateIds()
+ self.sentences[-1].id = -1
+
+class Paragraph( RawParagraph ):
+
+ def __init__(self, paragraph_data, buf, insertioniter):
+ id = paragraph_data.id
+ source_article_id = paragraph_data.source_article_id
+ source_section_id = paragraph_data.source_section_id
+ source_paragraph_id = paragraph_data.source_paragraph_id
+
+ sentences = []
+
+ insertionmark = buf.create_mark(None, insertioniter, False)
+ for sentence_data in paragraph_data.sentences_data:
+ insertioniter = buf.get_iter_at_mark(insertionmark)
+ if sentence_data.type == "sentence":
+ sentence = Sentence(sentence_data, buf, insertioniter)
+ elif sentence_data.type == "picture":
+ sentence = Picture(sentence_data, buf, insertioniter)
+ else:
+ print "WARNING, WEIRD SENTENCES: %s" % (sentence_data.type, )
+ sentences.append(sentence)
+
+ insertioniter = buf.get_iter_at_mark(insertionmark)
+ endsentencedata = Sentence_Data(id = -1, text = "\n")
+ sentences.append(Sentence(endsentencedata, buf, insertioniter))
+
+ buf.delete_mark(insertionmark)
+
+ RawParagraph.__init__(self, id, source_article_id, source_section_id, source_paragraph_id, sentences, buf)
+
+
+class dummyParagraph( Paragraph ):
+ def __init__(self, buf, insertioniter, leftgravity):
+ self.id = -1
+ self.source_article_id = -1
+ self.source_section_id = -1
+ self.source_paragraph_id = -1
+ self.buf = buf
+ self.sentences = [ dummySentence(buf, insertioniter, leftgravity) ] \ No newline at end of file
diff --git a/Processing/Article/Section.py b/Processing/Article/Section.py
new file mode 100644
index 0000000..aecae66
--- /dev/null
+++ b/Processing/Article/Section.py
@@ -0,0 +1,324 @@
+# Copyright (C) IBM Corporation 2008
+
+from Processing.Article.Paragraph import *
+
+"""
+Created by Jonathan Mace
+
+The classes here each correspond to a sentence in the given text buffer.
+
+You should not instantiate these classes directly.
+
+Use the "level above" class or the Article class to apply changes to the textbuffer
+or structure of the article.
+
+"""
+
+"""
+a Section instance contains a list of paragraphs. It has methods for inserting,
+deleting and rearranging paragraphs within itself, as well as other housekeeping
+functions.
+
+"""
+
+class RawSection:
+
+ def __init__(self, id, source_article_id, source_section_id, paragraphs, buf):
+ self.id = id
+ self.source_article_id = source_article_id
+ self.source_section_id = source_section_id
+ self.paragraphs = paragraphs
+ self.buf = buf
+
+ def insertParagraph(self, paragraph_data, lociter):
+ insertionindex = self.__get_best_paragraph(lociter)
+ insertioniter = self.paragraphs[insertionindex].getStart()
+ paragraph = Paragraph(paragraph_data, self.buf, insertioniter)
+ self.paragraphs.insert(insertionindex, paragraph)
+
+ def deleteParagraph(self, lociter):
+ deletionindex = self.__get_exact_paragraph(lociter)
+ if deletionindex != len(self.paragraphs) - 1:
+ paragraph = self.paragraphs[deletionindex]
+ paragraph.delete()
+ del self.paragraphs[deletionindex]
+ if len(self.paragraphs) == 1:
+ return True
+ else:
+ return False
+
+ def removeParagraph(self, lociter):
+ removalindex = self.__get_exact_paragraph(lociter)
+ if removalindex != len(self.paragraphs) - 1:
+ paragraph = self.paragraphs[removalindex]
+ paragraph.delete()
+ del self.paragraphs[removalindex]
+ if len(self.paragraphs) == 1:
+ return True
+ else:
+ return False
+
+ def splitParagraph(self, lociter):
+ paragraphindex = self.__get_exact_paragraph(lociter)
+ paragraph = self.paragraphs[paragraphindex]
+ source_article_id = paragraph.source_article_id
+ source_section_id = paragraph.source_section_id
+ source_paragraph_id = paragraph.source_paragraph_id
+ firstdata = paragraph.getDataRange(paragraph.getStart(), lociter)
+ seconddata = paragraph.getDataRange(lociter, paragraph.getEnd())
+ mark = self.buf.create_mark(None, lociter, False)
+ if firstdata != [] and seconddata != []:
+ self.deleteParagraph(lociter)
+
+ insertioniter = self.buf.get_iter_at_mark(mark)
+ paragraphdata = Paragraph_Data(None, source_article_id, source_section_id, source_paragraph_id, firstdata)
+ paragraph = Paragraph(paragraphdata, self.buf, insertioniter)
+ self.paragraphs.insert(paragraphindex, paragraph)
+
+ insertioniter = self.buf.get_iter_at_mark(mark)
+ paragraphdata = Paragraph_Data(None, source_article_id, source_section_id, source_paragraph_id, seconddata)
+ paragraph = Paragraph(paragraphdata, self.buf, insertioniter)
+ self.paragraphs.insert(paragraphindex+1, paragraph)
+
+
+
+
+ def delete(self):
+ for paragraph in self.paragraphs:
+ paragraph.delete()
+
+ def remove(self):
+ for paragraph in self.paragraphs:
+ paragraph.remove()
+
+ def deleteSelection(self, startiter, enditer):
+ startindex = self.__get_exact_paragraph(startiter)
+ endindex = self.__get_exact_paragraph(enditer)
+ if endindex == len(self.paragraphs)-1:
+ endindex = endindex - 1
+ if startindex == endindex:
+ empty = self.paragraphs[startindex].deleteSelection(startiter, enditer)
+ if empty:
+ self.paragraphs[startindex].delete()
+ del self.paragraphs[startindex]
+ elif startindex < endindex:
+ startmark = self.buf.create_mark(None, startiter, True)
+ endmark = self.buf.create_mark(None, enditer, True)
+
+ endparagraph = self.paragraphs[endindex]
+ empty = endparagraph.deleteSelection(endparagraph.getStart(), self.buf.get_iter_at_mark(endmark))
+ if empty:
+ self.paragraphs[endindex].delete()
+ del self.paragraphs[endindex]
+ self.buf.delete_mark(endmark)
+
+ for i in range(startindex+1, endindex):
+ self.paragraphs[startindex+1].delete()
+ del self.paragraphs[startindex+1]
+
+ startparagraph = self.paragraphs[startindex]
+ empty = startparagraph.deleteSelection(self.buf.get_iter_at_mark(startmark), startparagraph.getEnd())
+ if empty:
+ self.paragraphs[startindex].delete()
+ del self.paragraphs[startindex]
+ self.buf.delete_mark(startmark)
+ if len(self.paragraphs) == 1:
+ return True
+ else:
+ return False
+
+
+ def getParagraph(self, lociter):
+ paragraphindex = self.__get_exact_paragraph(lociter)
+ return self.paragraphs[paragraphindex]
+
+ def getBestParagraph(self, lociter):
+ paragraphindex = self.__get_best_paragraph(lociter)
+ if paragraphindex == len(self.paragraphs):
+ return self.paragraphs[-1]
+ else:
+ return self.paragraphs[paragraphindex]
+
+ def getStart(self):
+ return self.paragraphs[0].getStart()
+
+ def getEnd(self):
+ return self.paragraphs[-1].getEnd()
+
+ def __get_best_paragraph(self, lociter):
+ paragraphindex = self.__get_exact_paragraph(lociter)
+ paragraph = self.paragraphs[paragraphindex]
+ left = paragraph.getStart().get_offset()
+ middle = lociter.get_offset()
+ right = paragraph.getEnd().get_offset()
+ leftdist = middle - left
+ rightdist = right - middle
+
+ if (paragraphindex < len(self.paragraphs)) and (leftdist > rightdist):
+ paragraphindex = paragraphindex +1
+ return paragraphindex
+
+ def __get_exact_paragraph(self, lociter):
+ i = 0
+ for i in range(len(self.paragraphs)-1):
+ start = self.paragraphs[i+1].getStart()
+ if lociter.compare(start) == -1:
+ return i
+ return len(self.paragraphs)-1
+
+ def getId(self):
+ return self.id
+
+ def getData(self):
+ id = self.id
+ source_article_id = self.source_article_id
+ source_section_id = self.source_section_id
+ paragraphs_data = []
+ for paragraph in self.paragraphs[0:len(self.paragraphs)-1]:
+ paragraphs_data.append(paragraph.getData())
+
+ data = Section_Data(id, source_article_id, source_section_id, paragraphs_data)
+ return data
+
+ def getDataRange(self, startiter, enditer):
+ startindex = self.__get_exact_paragraph(startiter)
+ endindex = self.__get_exact_paragraph(enditer)
+ if startindex == endindex:
+ return self.paragraphs[startindex].getDataRange(startiter, enditer)
+ else:
+ startdata = []
+ startparagraph = self.paragraphs[startindex]
+ if startiter.compare(startparagraph.getStart()) == 0:
+ startdata.append(self.paragraphs[startindex].getData())
+ else:
+ startdata.extend(startparagraph.getDataRange(startiter, startparagraph.getEnd()))
+ dummydata = Sentence_Data(id = -1, text = "")
+ startdata.append(dummydata)
+
+ middledata = []
+ for paragraph in self.paragraphs[startindex+1:endindex]:
+ middledata.append(paragraph.getData())
+
+ enddata = []
+ if endindex != len(self.paragraphs):
+ endparagraph = self.paragraphs[endindex]
+ enddata.extend(endparagraph.getDataRange(endparagraph.getStart(), enditer))
+
+ data = startdata + middledata + enddata
+
+ return data
+
+ def mark(self):
+ markiter = self.getStart()
+ self.markmark = self.buf.create_mark(None, markiter, True)
+ arrow = gtk.gdk.pixbuf_new_from_xpm_data(arrow_xpm)
+ self.buf.insert_pixbuf(markiter, arrow)
+
+ def unmark(self):
+ markiter = self.buf.get_iter_at_mark(self.markmark)
+ markenditer = self.buf.get_iter_at_offset(markiter.get_offset()+1)
+ self.buf.delete(markiter, markenditer)
+ self.buf.delete_mark(self.markmark)
+
+ def getParagraphs(self):
+ return self.paragraphs
+
+ def pad(self):
+ # Pad adds a dummy paragraph containing the sentence " ", to this section
+ insertioniter = self.paragraphs[-1].getStart()
+ dummydata = Sentence_Data(id = -1, text = " ")
+ dummyparagraphdata = Paragraph_Data(id = -1, sentences_data = [dummydata])
+ paragraph = Paragraph(dummyparagraphdata, self.buf, insertioniter)
+ self.paragraphs.insert(-1, paragraph)
+
+ def clean(self):
+ # Removes the effects of pad.
+ # Returns true if, after removing the pad, the section has no meaningful content and can therefore be destroyed
+ if len(self.paragraphs) > 1:
+ paragraph = self.paragraphs[-2]
+ paragraphisempty = paragraph.clean()
+ if paragraphisempty:
+ del self.paragraphs[-2]
+ if len(self.paragraphs) == 1:
+ return True
+ else:
+ return False
+ else:
+ return True
+
+ def getText(self):
+ return self.buf.get_slice(self.getStart(), self.getEnd())
+
+ def checkIntegrity(self, nextiter):
+ i = 0
+ paragraphs = []
+ while i < len(self.paragraphs) - 1:
+ paragraph = self.paragraphs[i]
+ nextparagraph = self.paragraphs[i+1]
+
+ if paragraph.getStart().compare(nextparagraph.getStart()) == -1:
+ text = self.buf.get_slice(paragraph.getStart(), nextparagraph.getStart())
+ if len(text) > 0 and text[-1] != "\n":
+ print "concatenating paragraphs"
+ nextparagraph.sentences = paragraph.sentences + nextparagraph.sentences
+ else:
+ paragraphs.extend(paragraph.checkIntegrity(nextparagraph.getStart()))
+ else:
+ paragraph.remove()
+ del self.paragraphs[i]
+ i = i - 1
+
+ i = i + 1
+
+ paragraph = self.paragraphs[-1]
+
+ if paragraph.getStart().compare(nextiter) == -1:
+ paragraphs.extend(paragraph.checkIntegrity(nextiter))
+
+ sections = []
+ paragraphstart = 0
+ for i in range(len(paragraphs)-1):
+ if paragraphs[i].getText() == "\n":
+ sections.append(RawSection(self.id, self.source_article_id, self.source_section_id, paragraphs[paragraphstart:i+1], self.buf))
+ paragraphstart = i + 1
+ sections.append(RawSection(self.id, self.source_article_id, self.source_section_id, paragraphs[paragraphstart:len(paragraphs)], self.buf))
+
+ return sections
+
+ def generateIds(self):
+ if self.id == None or self.id == -1:
+ self.id = random.randint(100, 100000)
+ for paragraph in self.paragraphs[0:len(self.paragraphs)]:
+ paragraph.generateIds()
+ self.paragraphs[-1].id = -1
+
+class Section( RawSection ):
+
+ def __init__(self, section_data, buf, insertioniter):
+ id = section_data.id
+ source_article_id = section_data.source_article_id
+ source_section_id = section_data.source_section_id
+
+ paragraphs = []
+ insertionmark = buf.create_mark(None, insertioniter, False)
+
+ for paragraph_data in section_data.paragraphs_data:
+ insertioniter = buf.get_iter_at_mark(insertionmark)
+ paragraphs.append(Paragraph(paragraph_data, buf, insertioniter))
+
+ insertioniter = buf.get_iter_at_mark(insertionmark)
+ endparagraphdata = Paragraph_Data(id = 1, sentences_data = [])
+ paragraphs.append(Paragraph(endparagraphdata, buf, insertioniter))
+
+ buf.delete_mark(insertionmark)
+
+ RawSection.__init__(self, id, source_article_id, source_section_id, paragraphs, buf)
+
+class dummySection(Section):
+ def __init__(self, buf, insertioniter, leftgravity):
+ self.id = -1
+ self.source_article_id = -1
+ self.source_section_id = -1
+ self.buf = buf
+ self.paragraphs = [ dummyParagraph(buf, insertioniter, leftgravity) ]
+
diff --git a/Processing/Article/Sentence.py b/Processing/Article/Sentence.py
new file mode 100644
index 0000000..3b11d5a
--- /dev/null
+++ b/Processing/Article/Sentence.py
@@ -0,0 +1,200 @@
+# Copyright (C) IBM Corporation 2008
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+from Article_Data import *
+
+"""
+Created by Jonathan Mace
+
+The classes here each correspond to a sentence in the given text buffer.
+
+You should not instantiate these classes directly.
+
+Use the "level above" class or the Article class to apply changes to the textbuffer
+or structure of the article.
+
+"""
+
+"""
+A sentence keeps textmarks corresponding to the start and end of the sentence in the buffer.
+
+It has methods for restructuring itself in the event that the textbuffer changes
+from an action not controlled by the Article object it is contained in.
+
+"""
+
+
+
+class RawSentence:
+
+ def __init__(self, id, source_article_id, source_section_id, source_paragraph_id, source_sentence_id, buf, formatting, leftmark, rightmark):
+ self.id = id
+ self.source_article_id = source_article_id
+ self.source_section_id = source_section_id
+ self.source_paragraph_id = source_paragraph_id
+ self.source_sentence_id = source_sentence_id
+ self.buf = buf
+ self.formatting = formatting
+ self.leftmark = leftmark
+ self.rightmark = rightmark
+ self.type = "sentence"
+
+ def generateIds(self):
+ if self.id == None or self.id == -1:
+ self.id = random.randint(100, 100000)
+
+ def delete(self):
+ b = self.buf
+ l = b.get_iter_at_mark(self.leftmark)
+ r = b.get_iter_at_mark(self.rightmark)
+ b.delete(l, r)
+ b.delete_mark(self.leftmark)
+ b.delete_mark(self.rightmark)
+
+ def remove(self):
+ b = self.buf
+ b.delete_mark(self.leftmark)
+ b.delete_mark(self.rightmark)
+
+ def getStart(self):
+ return self.buf.get_iter_at_mark(self.leftmark)
+
+ def getEnd(self):
+ return self.buf.get_iter_at_mark(self.rightmark)
+
+ def getId(self):
+ return self.id
+
+ def getData(self):
+ id = self.id
+ source_article_id = self.source_article_id
+ source_section_id = self.source_section_id
+ source_paragraph_id = self.source_paragraph_id
+ source_sentence_id = self.source_sentence_id
+ text = self.getText()
+ formatting = self.formatting
+
+ data = Sentence_Data(id, source_article_id, source_section_id, source_paragraph_id, source_sentence_id, text, formatting)
+ return data
+
+ def getText(self):
+ return self.buf.get_slice(self.getStart(), self.getEnd())
+
+ def checkIntegrity(self, nextiter):
+ text = unicode(self.buf.get_slice(self.getStart(), nextiter))
+ lines = text.splitlines(True)
+ sentencestartoffset = self.getStart().get_offset()
+ sentences = []
+ if text == "":
+ return []
+ else:
+ for line in lines:
+ if line == "":
+ pass
+ elif line == "\n":
+ startmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset), False)
+ endmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset + 1), True)
+ sentences.append(RawSentence(self.id, self.source_article_id, self.source_section_id, self.source_paragraph_id, self.source_sentence_id, self.buf, self.formatting, startmark, endmark))
+ sentencestartoffset = sentencestartoffset + 1
+ elif line[-1] == "\n":
+ startmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset), False)
+ endmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset + len(line)-1), True)
+ sentences.append(RawSentence(self.id, self.source_article_id, self.source_section_id, self.source_paragraph_id, self.source_sentence_id, self.buf, self.formatting, startmark, endmark))
+ sentencestartoffset = sentencestartoffset + len(line)-1
+ startmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset), False)
+ endmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset + 1), True)
+ sentences.append(RawSentence(self.id, self.source_article_id, self.source_section_id, self.source_paragraph_id, self.source_sentence_id, self.buf, self.formatting, startmark, endmark))
+ sentencestartoffset = sentencestartoffset + 1
+ else:
+ startmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset), False)
+ endmark = self.buf.create_mark(None, self.buf.get_iter_at_offset(sentencestartoffset + len(line)), True)
+ sentences.append(RawSentence(self.id, self.source_article_id, self.source_section_id, self.source_paragraph_id, self.source_sentence_id, self.buf, self.formatting, startmark, endmark))
+
+ return sentences
+
+class Sentence( RawSentence ):
+
+ def __init__(self, sentence_data, buf, insertioniter):
+
+ id = sentence_data.id
+ source_article_id = sentence_data.source_article_id
+ source_section_id = sentence_data.source_section_id
+ source_paragraph_id = sentence_data.source_paragraph_id
+ source_sentence_id = sentence_data.source_sentence_id
+
+ """
+ Here, apply formatting changes when necessary.
+ Yet to be implemented. """
+ formatting = sentence_data.formatting
+
+ rightmark = buf.create_mark(None, insertioniter, True)
+ leftmark = buf.create_mark(None, insertioniter, False)
+ buf.insert(insertioniter, unicode(sentence_data.text))
+ left = buf.get_iter_at_mark(rightmark)
+ right = buf.get_iter_at_mark(leftmark)
+ buf.move_mark(leftmark, left)
+ buf.move_mark(rightmark, right)
+
+ RawSentence.__init__(self, id, source_article_id, source_section_id, source_paragraph_id, source_sentence_id, buf, formatting, leftmark, rightmark)
+
+class Picture( RawSentence ):
+
+ def __init__(self, picture_data, buf, insertioniter):
+ id = 0
+ source_article_id = picture_data.source_article_id
+ source_section_id = 0
+ source_paragraph_id = 0
+ source_sentence_id = 0
+ formatting = []
+
+ self.text = picture_data.text
+
+ rightmark = buf.create_mark(None, insertioniter, True)
+ leftmark = buf.create_mark(None, insertioniter, False)
+
+ pixbuf = gtk.gdk.pixbuf_new_from_file(picture_data.text)
+ buf.insert_pixbuf(insertioniter, pixbuf)
+
+ left = buf.get_iter_at_mark(rightmark)
+ right = buf.get_iter_at_mark(leftmark)
+ buf.move_mark(leftmark, left)
+ buf.move_mark(rightmark, right)
+
+ RawSentence.__init__(self, id, source_article_id, source_section_id, source_paragraph_id, source_sentence_id, buf, formatting, leftmark, rightmark)
+ self.type = "picture"
+
+ def getData(self):
+ return Picture_Data(self.source_article_id, self.text)
+
+ def checkIntegrity(self, nextiter):
+ sentences = []
+ if self.getEnd().compare(nextiter) == 0:
+ return [self]
+ elif self.getStart().compare(self.getEnd()) > 0:
+ sentences.append(self)
+ if self.getEnd().compare(nextiter) > 0:
+ startmark = self.buf.create_mark(None, self.getEnd(), False)
+ endmark = self.buf.create_mark(None, nextiter, True)
+ nextsentence = RawSentence(self.source_article_id, 1, 1, 1, self.buf, [], startmark, endmark)
+ nextsentences = nextsentence.checkIntegrity(nextiter)
+ sentences.extend(nextsentences)
+ return sentences
+
+
+class dummySentence( Sentence ):
+ def __init__(self, buf, insertioniter, leftgravity):
+ self.id = -1
+ self.source_article_id = -1
+ self.source_section_id = -1
+ self.source_paragraph_id = -1
+ self.source_sentence_id = -1
+ self.text = ""
+ self.formatting = []
+ self.buf = buf
+ self.leftmark = self.buf.create_mark(None, insertioniter, leftgravity)
+ self.rightmark = self.buf.create_mark(None, insertioniter, leftgravity)
+ self.type = "dummysentence"
+ \ No newline at end of file
diff --git a/Processing/Article/__init__.py b/Processing/Article/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Processing/Article/__init__.py
diff --git a/Processing/Article_Builder.py b/Processing/Article_Builder.py
new file mode 100644
index 0000000..2b83c18
--- /dev/null
+++ b/Processing/Article_Builder.py
@@ -0,0 +1,234 @@
+# Copyright (C) IBM Corporation 2008
+
+from BeautifulSoup import Tag
+from NewtifulSoup import NewtifulStoneSoup as BeautifulStoneSoup
+from Processing.Article.Article_Data import *
+import re
+import IO_Manager
+
+class Article_Builder:
+ """
+ Created by Christopher Leonard.
+
+ ID descriptions:
+ 0 - picture
+ 1 - heading
+ > 1 - anything
+
+ This class converts between DITA and article_data representation of articles. Badly in need of refactoring!
+ """
+
+
+
+ def get_article_from_dita(self, dita):
+ """
+ This method takes an article in DITA format as input, parses the DITA, and outputs the corresponding article_data object
+ """
+ workingDir = IO_Manager.IO_Manager().workingDir
+ self.sentences = []
+ has_shortdesc = False
+ input = BeautifulStoneSoup(dita)
+ article_id = input.resourceid['id']
+ current_section_id = ""
+ current_p_id = ""
+ sentence_data_list = []
+ paragraph_data_list = []
+ section_data_list = []
+ if input.find("shortdesc") != None:
+ paragraph_data=[]
+ for ph in input.shortdesc.findAll("ph"):
+ id = ph['id']
+ source_sentence_id = id
+ source_paragraph_id = "shortdesc"
+ source_section_id = "shortdesc"
+ source_article_id = article_id
+ text = ph.renderContents().replace("\n", "").replace("&amp;#160;", "").strip() + " "
+ if text[0:5] == "Satur":
+ print unicode(text)
+ sentence_data = Sentence_Data(id, source_article_id, source_section_id, source_paragraph_id, source_sentence_id, text)
+ sentence_data_list.append(sentence_data)
+ paragraph_data.append(Paragraph_Data("shortdesc", article_id, "shortdesc", "shortdesc", sentence_data_list))
+ section_data = Section_Data("shortdesc", article_id, "shortdesc", paragraph_data)
+ section_data_list.append(section_data)
+ sentence_data_list = []
+ input.shortdesc.extract()
+ has_shortdesc = True
+ taglist = input.findAll(re.compile("refbody|section|p|ph|image"))
+ for i in xrange(len(taglist)):
+ tag = taglist[len(taglist) - i - 1]
+ if tag.name == "ph":
+ id = tag['id']
+ source_sentence_id = id
+ source_paragraph_id = current_p_id
+ source_section_id = current_section_id
+ source_article_id = article_id
+ text = tag.renderContents().replace("\n", "").replace("&amp;#160;", "").strip() + " "
+ sentence_data = Sentence_Data(id, source_article_id, source_section_id, source_paragraph_id, source_sentence_id, text)
+ sentence_data_list.insert(0, sentence_data)
+ elif tag.name == "p":
+ if not tag.has_key("id"):
+ id = -1
+ else:
+ id = tag['id']
+ source_paragraph_id = id
+ source_section_id = current_section_id
+ source_article_id = article_id
+ paragraph_data = Paragraph_Data(id, source_article_id, source_section_id, source_paragraph_id, sentence_data_list)
+ paragraph_data_list.insert(0, paragraph_data)
+ sentence_data_list = []
+ current_p_id = id
+ elif tag.name == "refbody" :
+ if tag.findParent("reference").has_key("id"):
+ id = "r" + tag.findParent("reference")['id']
+ else:
+ id = "r90000"
+ source_section_id = id
+ source_article_id = article_id
+ section_data = Section_Data(id, source_article_id, source_section_id, paragraph_data_list)
+ if has_shortdesc:
+ section_data_list.insert(1,section_data)
+ else:
+ section_data_list.insert(0,section_data)
+ if tag.findChild("title", recursive=False) != None:
+ heading = tag.findChild('title').renderContents().replace("\n", "").replace("&amp;#160;", "").strip()
+ sen = Sentence_Data(1, source_article_id, source_section_id, 1, 1, heading)
+ par = Paragraph_Data(1, source_article_id, source_section_id, 1, [sen])
+ headingdata = Section_Data(1, source_article_id, source_section_id, [par])
+
+ if has_shortdesc:
+ section_data_list.insert(1,headingdata)
+ else:
+ section_data_list.insert(0,headingdata)
+ paragraph_data_list = []
+ current_section_id = tag.name[0] + id
+
+ elif tag.name == "section":
+ id = "s" + tag['id']
+ source_section_id = id
+ source_article_id = article_id
+
+ section_data = Section_Data(id, source_article_id, source_section_id, paragraph_data_list)
+ if has_shortdesc:
+ section_data_list.insert(1,section_data)
+ else:
+ section_data_list.insert(0,section_data)
+ if tag.findChild("title", recursive=False) != None:
+ heading = tag.findChild('title').renderContents().replace("\n", "").replace("&amp;#160;", "").strip()
+ sen = Sentence_Data(1, source_article_id, source_section_id, 1, 1, heading)
+ par = Paragraph_Data(1, source_article_id, source_section_id, 1, [sen])
+ headingdata = Section_Data(1, source_article_id, source_section_id, [par])
+
+ if has_shortdesc:
+ section_data_list.insert(1,headingdata)
+ else:
+ section_data_list.insert(0,headingdata)
+ paragraph_data_list = []
+ current_section_id = id
+
+ elif tag.name == "image":
+
+ if tag.parent.name == "p":
+ source_article_id = article_id
+ text = tag['href'].replace("..", workingDir)
+ picture_data = Picture_Data(source_article_id, text)
+ sentence_data_list.insert(0, picture_data)
+
+ article_title = input.find("title").renderContents().replace("\n", "").strip()
+
+ image_list = []
+ imglist_tag = input.find(True, attrs={"id" : "imagelist"})
+ if imglist_tag != None:
+ for img in imglist_tag.findAll("image"):
+ caption = img.findChild("alt")
+ if caption != None:
+ caption = caption.renderContents().replace("\n", "").strip()
+ else:
+ caption = ""
+ image_list.append((img['href'], caption))
+
+ data = Article_Data(article_id, article_id, article_title, "theme", section_data_list, image_list)
+
+ return data
+
+
+ def get_dita_from_article(self, article):
+ """
+ This method takes as input an instance of the Article class.
+ It calls the getData method of the article class to get the article_data representation of the article.
+ It then constructs the corresponding DITA representation of the article.
+ """
+ workingDir = IO_Manager.IO_Manager().workingDir
+ article_data = article.getData()
+ output = BeautifulStoneSoup("<?xml version='1.0' encoding='utf-8'?><!DOCTYPE reference PUBLIC \"-//IBM//DTD DITA IBM Reference//EN\" \"ibm-reference.dtd\"><reference><title>%s</title><prolog></prolog></reference>" % article_data.article_title)
+ current_ref = output.reference
+ current_title = None
+ for section in article_data.sections_data:
+ #headings check
+ if len(section.paragraphs_data) == 1 and len(section.paragraphs_data[0].sentences_data) == 1 and section.paragraphs_data[0].sentences_data[0].id == 1:
+ paragraph = section.paragraphs_data[0]
+ current_title = paragraph.sentences_data[0].text
+ elif str(section.id).startswith("r"):
+ reference_tag = self.tag_generator(output, "reference", attrs=[("id", section.id.replace("r", ""))])
+ if current_title != None:
+ reference_tag.append(self.tag_generator(output, "title", contents=current_title))
+ current_title = None
+ reference_tag.append(self.tag_generator(output, "refbody"))
+ for paragraph in section.paragraphs_data:
+ if paragraph.id == "shortdesc":
+ paragraph_tag = self.tag_generator(output, "shortdesc")
+ else:
+ paragraph_tag = self.tag_generator(output, "p", attrs=[("id", str(paragraph.id))])
+ for sentence in paragraph.sentences_data:
+ ph_tag = self.tag_generator(output, "ph", attrs=[("id", str(sentence.id))], contents = sentence.text)
+ paragraph_tag.append(ph_tag)
+ reference_tag.refbody.append(paragraph_tag)
+ output.reference.append(reference_tag)
+ current_ref = reference_tag.refbody
+ else:
+ if section.id == "shortdesc":
+ section_tag = self.tag_generator(output, "section", attrs=[("id", "shortdesc")])
+ else:
+ section_tag = self.tag_generator(output, "section", attrs=[("id", str(section.id).replace("s", ""))])
+ if current_title != None:
+ section_tag.append(self.tag_generator(output, "title", contents=current_title))
+ current_title = None
+ for paragraph in section.paragraphs_data:
+ paragraph_tag = self.tag_generator(output, "p", attrs=[("id", str(paragraph.id))])
+ for sentence in paragraph.sentences_data:
+ if sentence.type == "sentence":
+ ph_tag = self.tag_generator(output, "ph", attrs=[("id", str(sentence.id))], contents = sentence.text)
+ paragraph_tag.append(ph_tag)
+ elif sentence.type == "picture":
+ # switch image to relative path
+ image_tag = self.tag_generator(output, "image", attrs=[("href", sentence.text.replace(workingDir, ".."))])
+ paragraph_tag.append(image_tag)
+ else:
+ print sentence.type
+
+ section_tag.append(paragraph_tag)
+ current_ref.append(section_tag)
+ if current_title != None:
+ current_ref.append('<section id="56756757"><p id="6875534"><ph id="65657657">%s</ph></p></section>' % current_title)
+ current_title = None
+ if article_data.image_list != []:
+ for unnecessary_tag in output.findAll(True, attrs={"id" : "imagelist"}):
+ unnecessary_tag.extract()
+ image_list = self.tag_generator(output, "reference", [("id", "imagelist")])
+ output.reference.append(image_list)
+ image_list_body = self.tag_generator(output, "refbody")
+ image_list.append(image_list_body)
+ for image in article_data.image_list:
+ image_tag = self.tag_generator(output, "image", [("href", image[0])], "<alt>" + image[-1] + "</alt>")
+ image_list_body.append(image_tag)
+ dita = output.prettify()
+ return dita
+
+ def tag_generator(self, soup, name, attrs=[], contents=None):
+ if attrs != []:
+ new_tag = Tag(soup, name, attrs)
+ else:
+ new_tag = Tag(soup, name)
+ if contents != None:
+ new_tag.insert(0, contents)
+ return new_tag
+ \ No newline at end of file
diff --git a/Processing/HTML_Parser.py b/Processing/HTML_Parser.py
new file mode 100644
index 0000000..6163c68
--- /dev/null
+++ b/Processing/HTML_Parser.py
@@ -0,0 +1,256 @@
+# Copyright (C) IBM Corporation 2008
+
+from BeautifulSoup import BeautifulSoup, Tag
+from NewtifulSoup import NewtifulStoneSoup as BeautifulStoneSoup
+import re
+from datetime import date
+
+class NoDocException(Exception):
+ def __init__(self, value):
+ self.parameter = value
+ def __str__(self):
+ return repr(self.parameter)
+
+"""
+Wrap Beautiful Soup HTML parser up in custom class to add some
+Media Wiki and DITA specific parsing functionality.
+"""
+class HTML_Parser:
+
+ #=======================================================================
+ # These lists are used at the pre-parsing stage
+ keep_tags = [ "html", "body", "p", "h1", "h2", "h3", "h4", "h5", "h6",\
+ "img", "table", "tr", "th", "td", "ol", "ul", "li", "sup", "sub"]
+ remove_tags_keep_content= ["div", "span", "strong", "a", "i", "b", "u", "color", "font"]
+ remove_classes_regexp = ""
+ #=======================================================================
+
+ #=======================================================================
+ # These lists are used at the parsing stage
+ root_node = "body"
+ section_separators = ["h3", "h4", "h5"]
+ reference_separators = ["h1", "h2"]
+ block_elements = ["img", "table", "ol", "ul"]
+ #=======================================================================
+
+ def __init__(self, document_to_parse, title, source_url):
+ if document_to_parse == None:
+ raise NoDocException("No content to parse - supply document to __init__")
+ self.input = BeautifulSoup(document_to_parse)
+ self.source = source_url
+ self.output_soup = BeautifulStoneSoup('<?xml version="1.0" encoding="utf-8"?><reference><title>%s</title></reference>' % title)
+ # First ID issued will be id below + 1
+ self.ids = {"reference" : 1,\
+ "section" : 1,\
+ "p" : 1,\
+ "ph" : 1\
+ }
+ self.image_list = self.tag_generator("reference", self.tag_generator("refbody"),[("id", "imagelist")])
+
+ def create_paragraph(self, text, tag="p"):
+ """
+ Creates a new paragraph containing <ph> tags, surrounded by the specified tag
+ @param text: Text to mark up
+ @param tag: Tag to surround with (defaults to "p")
+ @return: new tag
+ """
+ new_para = self.tag_generator(tag)
+ sentences = re.split(re.compile("[\.\!\?\"] "), text)
+ separators = re.findall(re.compile("[\.\!\?\"](?= )"), text)
+ for i in range(len(sentences) - 1):
+ new_para.append(self.tag_generator("ph", sentences[i] + separators[i]))
+ new_para.append(self.tag_generator("ph", sentences[-1]))
+ return new_para
+
+ def get_publisher(self):
+ """
+ Extracts publisher from source URL
+ @return: name of publisher
+ """
+ output = self.source.replace("http://", "").split("/")[0].split(".")
+ return ".".join([output[-2], output[-1]])
+
+ def image_handler(self):
+ """
+ Extracts image tags from the document
+ """
+ for img in self.input.findAll("img"):
+ too_small = False
+ image_path = img['src']
+ alt_text = ""
+ if img.has_key("width") and img.has_key("height") and int(img['width']) <= 70 and int(img['height']) <= 70:
+ too_small = True
+ if img.has_key("alt") and img['alt'] != "":
+ alt_text = img['alt']
+ else:
+ alt_text = image_path.split("/")[-1]
+ if (not too_small) and self.image_list.refbody.find(attrs={"href" : image_path}) == None:
+ self.image_list.refbody.append(self.tag_generator("image", "<alt>%s</alt>" % alt_text, [("href", image_path)]))
+ img.extract()
+
+ def make_shortdesc(self):
+ """
+ Extracts 1st paragraph from input, and makes it a 'shortdesc' tag
+ @return: new <shortdesc> tag containing contents of 1st paragraph
+ """
+ paragraphs = self.input.findAll("p")
+ for p in paragraphs:
+ contents = p.renderContents()
+ if len(contents) > 20 and (("." in contents) or ("?" in contents) or ("!" in contents)):
+ p.extract()
+ return self.create_paragraph(contents, "shortdesc")
+ return self.tag_generator("shortdesc")
+
+ def parse(self):
+ """
+ parses the document
+ @return: String of document in DITA markup
+ """
+ #remove images
+ self.image_handler()
+ # pre-parse
+ self.pre_parse()
+ #identify the containing reference tag
+ output_reference = self.output_soup.find("reference")
+ #add the short description
+ output_reference.append(self.make_shortdesc())
+ #add the <prolog> tag to hold metadata
+ output_reference.append(self.tag_generator("prolog"))
+ #add the source url
+ output_reference.prolog.append('<source href="%s" />' % self.source)
+ #add the publisher
+ output_reference.prolog.append(self.tag_generator("publisher", self.get_publisher()))
+ the_date = date.today().strftime("%Y-%m-%d")
+ #add created and modified dates
+ output_reference.prolog.append(self.tag_generator('critdates', '<created date="%s" /><revised modified="%s" />' % (the_date, the_date)))
+ #add the first refbody
+ output_reference.append(self.tag_generator("refbody"))
+ #track whether text should be inserted in a section or into the refbody
+ in_section = False
+ #set current refbody and section pointers
+ current_refbody = output_reference.refbody
+ current_section = None
+ #call specialised method (redundant in this class, used for inheritance)
+ self.specialise()
+ #find the first tag
+ tag = self.input.find(self.root_node).findChild()
+ while tag != None:
+ #set variable to avoid hammering the string conversion function
+ tag_name = tag.name
+ #for debugging:
+ #ignore the root node
+ if tag_name == self.root_node:
+ pass
+ #paragraph action:
+ elif tag_name == "p":
+ if in_section:
+ #tag contents as sentences and add to current section
+ current_section.append(self.create_paragraph(tag.renderContents()))
+ else:
+ #tag contents as sentences and add to current refbody
+ current_refbody.append(self.create_paragraph(tag.renderContents()))
+ #section separator action
+ elif tag_name in self.section_separators:
+ #create a new section tag
+ new_section = self.tag_generator("section")
+ #make a title for the tag from heading contents
+ new_section.append(self.tag_generator("title", tag.renderContents()))
+ #hold a pointer to the new section
+ current_section = new_section
+ #add the new section to the current refbody
+ current_refbody.append(new_section)
+ #currently working in a section, not a refbody
+ in_section = True
+ #reference separator action:
+ elif tag_name in self.reference_separators:
+ #no longer working in a section
+ in_section = False
+ #create a new reference tag
+ new_reference = self.tag_generator("reference")
+ #make a title for the tag from heading contents
+ new_reference.append(self.tag_generator("title", tag.renderContents()))
+ #create a refbody tag for the reference
+ new_refbody = self.tag_generator("refbody")
+ #add refbody to the reference tag
+ new_reference.append(new_refbody)
+ #remember the current refbody tag
+ current_refbody = new_refbody
+ #add the new reference to the containing reference tag in the output
+ output_reference.append(new_reference)
+ #block element action
+ elif tag_name in self.block_elements:
+ if in_section:
+ #add block element to current section
+ current_section.append(self.tag_generator(tag_name, tag.renderContents()))
+ else:
+ #add block element to new section
+ current_refbody.append(self.tag_generator("section", self.tag_generator(tag_name, tag.renderContents())))
+ #find the next tag and continue
+ tag = tag.findNextSibling()
+ #append the image list
+ self.output_soup.reference.append(self.image_list)
+ #return output as a properly indented string
+ return self.output_soup.prettify()
+
+ def pre_parse(self):
+ """
+ Prepares the input for parsing
+ """
+ for tag in self.input.findAll(True, recursive=False):
+ self.unTag(tag)
+
+ def specialise(self):
+ """
+ Allows for specialised calls when inheriting
+ """
+ pass
+
+ def tag_generator(self, tag, contents=None, attrs=[]):
+ """
+ Generates new tags for the output, adding IDs where appropriate
+ @param tag: name of new tag
+ @param contents: Optional, contents to add to tag
+ @param attrs: Optional, attributes to add to tag
+ @return: new Tag object
+ """
+ if self.ids.has_key(tag) and attrs == []:
+ self.ids[tag] += 1
+ attrs = [("id", str(self.ids[tag]))]
+ if attrs != []:
+ new_tag = Tag(self.output_soup, tag, attrs)
+ else:
+ new_tag = Tag(self.output_soup, tag)
+ if contents != None:
+ new_tag.insert(0, contents)
+ attrs = []
+ return new_tag
+
+ def unTag(self, tag):
+ """
+ recursively removes unwanted tags according to defined lists
+ @param tag: tag hierarchy to work on
+ """
+ for child in tag.findChildren(True, recursive=False):
+ self.unTag(child)
+ if (self.remove_classes_regexp != "") and (tag.has_key("class") and (re.match(self.remove_classes_regexp, tag["class"]) != None)):
+ tag.extract()
+ elif tag.name in self.keep_tags:
+ #newTag = Tag(self.input, tag.name)
+ #newTag.insert(0, tag.renderContents())
+ #tag.replaceWith(newTag)
+ pass
+ elif tag.name in self.remove_tags_keep_content:
+ children = tag.findChildren(True, recursive=False)
+ if len(children)==1:
+ tag.replaceWith(children[0])
+ elif len(children) > 1:
+ new_tag = Tag(self.input, "p")
+ for child in tag.findChildren(True, recursive=False):
+ new_tag.append(child)
+ tag.replaceWith(new_tag)
+ else:
+ tag.replaceWith(tag.renderContents())
+ else:
+ tag.extract()
+
+ \ No newline at end of file
diff --git a/Processing/IO_Manager.py b/Processing/IO_Manager.py
new file mode 100644
index 0000000..7cffced
--- /dev/null
+++ b/Processing/IO_Manager.py
@@ -0,0 +1,552 @@
+# Copyright (C) IBM Corporation 2008
+
+import gtk
+from BeautifulSoup import Tag
+from NewtifulSoup import NewtifulStoneSoup as BeautifulStoneSoup
+import os, platform, urllib
+from Article_Builder import Article_Builder
+from Processing.Article.Article import Article
+from MediaWiki_Helper import MediaWiki_Helper, PageNotFoundError
+from MediaWiki_Parser import MediaWiki_Parser
+import shutil
+import re
+
+class theme_not_found_error(Exception):
+ def __init__(self, value):
+ self.parameter = value
+ def __str__(self):
+ return repr(self.parameter)
+
+class page_not_found_error(Exception):
+ def __init__(self, value):
+ self.parameter = value
+ def __str__(self):
+ return repr(self.parameter)
+
+class theme_exists_error(Exception):
+ def __init__(self, value):
+ self.parameter = value
+ def __str__(self):
+ return repr(self.parameter)
+
+
+"""
+This class sits between the GUI and the back end (handling
+mediawiki communication and raw pages/theme/article modifications)
+"""
+class IO_Manager:
+
+ def __init__(self):
+ running_on = platform.system()
+ if running_on == "Windows":
+ # On Windows, used to save to a data subfolder of the folder that contains this code
+ #self.workingDir = os.path.join(__file__.rsplit("\\", 1)[0], "Data")
+ # but better to write to user home with os.getenv("USERPROFILE") or os.path.expanduser("~")
+ self.workingDir = os.path.join(os.getenv("USERPROFILE"), ".slicedata")
+ elif running_on == "Linux":
+ if "olpc" in platform.platform().lower():
+ from sugar.activity import activity
+ # On Sugar, save to the data subfolder of the app directory
+ self.workingDir = os.path.join(activity.get_activity_root(), "data")
+ print "Activity root is: %s" % str(activity.get_activity_root())
+ print "Data folder is: %s" % self.workingDir
+ else:
+ # On Linux, save to a .slicedata subdir of the user's homedir
+ self.workingDir = os.path.join(os.getenv("HOME"), ".slicedata")
+ self.proxies = {}
+ proxy_file = os.path.join(os.path.split(os.path.split(__file__)[0])[0], 'proxy.cfg')
+ if os.access(proxy_file, os.F_OK):
+ proxy_file_handle = open(proxy_file, "r")
+ for line in proxy_file_handle.readlines():
+ parts = line.split(':', 1)
+ #print "setting " + parts[0] + " proxy to " + parts[1]
+ self.proxies[parts[0].strip()] = parts[1].strip()
+ proxy_file_handle.close()
+ if self.proxies == {}:
+ self.proxies = None
+
+ def clean_title(self, title):
+ """
+ removes non-alphanumeric chars from titles and lowercases it
+ """
+ print "Cleaning: " + title
+ output = re.sub(re.compile('\W'), "_", title).lower()
+ print "Output: " + output
+ return output
+
+ def install_library(self):
+ if platform.system() == "Linux" and "olpc" in platform.platform().lower():
+ file_list = [('Lion (from en.wikipedia.org)', os.path.join(os.path.split(__file__)[0], "demolibrary", "lion-wikipedia.dita"), 'Wikipedia Articles'), ('Tiger (from en.wikipedia.org)', os.path.join(os.path.split(__file__)[0], "demolibrary", "tiger-wikipedia.dita"), 'Wikipedia Articles'), ('Giraffe (from en.wikipedia.org)', os.path.join(os.path.split(__file__)[0], "demolibrary", "giraffe-wikipedia.dita"), 'Wikipedia Articles'), ('Giraffe', os.path.join(os.path.split(__file__)[0], "demolibrary", "giraffe-blank.dita"), 'My Articles'), ('Zebra (from en.wikipedia.org)', os.path.join(os.path.split(__file__)[0], "demolibrary", "zebra-wikipedia.dita"), 'Wikipedia Articles')]
+ for file in file_list:
+ if file[2] not in self.get_themes():
+ print "install library: creating theme %s" % file[2]
+ self.add_theme_to_library(file[2])
+ print "install library: opening %s" % file[1]
+ open_file = open(file[1], "r")
+ contents = open_file.read()
+ open_file.close()
+ if contents:
+ print "install library: content read sucessfully"
+ print "install library: saving page %s" % file[0]
+ self.save_page(file[0], contents, file[2], get_images=True)
+ print "install library: save successful"
+
+ def __add_page_to_library(self, title, path, theme="My Articles"):
+ """
+ Adds a page to the library. If a theme is specified it is added to that theme, otherwise it is put into the 'No Assigned Theme' theme.
+
+ @param title: The title of the article to add to library.
+ @param path: The path of the article to add to library.
+ @param theme: Which theme to store the article in. (Optional, defaults to No Assigned Theme).
+ """
+ try:
+ #change to relative path
+ path = path.replace(os.path.join(self.workingDir, ""), "", 1)
+ map = self.load_map(theme)
+ existing_entry = map.find("topicref", attrs={"navtitle" : title})
+ if existing_entry != None:
+ existing_entry.extract()
+ map.map.append(Tag(map, "topicref", [("href", path), ("navtitle", title)]))
+ self.save_map(theme, map)
+ except Exception:
+ self.add_theme_to_library(theme)
+ self.__add_page_to_library(title, path, theme)
+
+ def add_theme_to_library(self, theme):
+ """
+ Adds themes to the library.
+ @param theme: Theme to add.
+ @raise theme_exists_error: If trying to add theme that already exists.
+ """
+ try:
+ map = self.load_map("Library")
+ # Ensure theme does not exist
+ if map.find(attrs={"navtitle" : theme}) == None:
+ # create a new entry in the library for the theme
+ map.map.append(Tag(map, "topicref", [("format", "ditamap"), ("href", "%s.ditamap" % self.clean_title(theme)), ("navtitle", theme)]))
+ # save the theme file
+ self.__create_map(theme)
+ else:
+ raise theme_exists_error("Theme already exists")
+ self.save_map("Library", map)
+ except theme_not_found_error:
+ # this error is caused by failing to open the library, so create the library and try again
+ self.__create_map("Library")
+ self.add_theme_to_library(theme)
+
+ def __create_map(self, map_name):
+ """
+ Creates a new map for the specified theme name.
+ @param map_name: name of map theme.
+ """
+ self.save_map(map_name, BeautifulStoneSoup(\
+ '<?xml version="1.0" encoding="utf-8"?>\
+ <!DOCTYPE map PUBLIC "-//IBM//DTD DITA IBM Map//EN" "ibm-map.dtd">\
+ <map title="%s">\
+ </map>' % map_name))
+
+ def download_wiki_article(self, title, theme, wiki=None, statuslabel = None):
+ """
+ manages downloading and saving of wiki articles.
+ @param title: Title of article to get
+ @param theme: Theme to save to
+ @param wiki: (optional) wiki to search - see MediaWiki helper for default behaviour
+ @param statuslabel: gtk status label to write to
+
+ """
+ if statuslabel != None:
+ statuslabel.set_label("%s download in progress..." % (title))
+ if wiki == None:
+ #article, url = MediaWiki_Helper().getArticleAsHTMLByTitle(title)
+ wiki = "en.wikipedia.org"
+
+ article, url = MediaWiki_Helper().getArticleAsHTMLByTitle(title, wiki)
+ if statuslabel != None:
+ statuslabel.set_label("Processing %s..." % (title))
+
+ parser = MediaWiki_Parser(article, title, url)
+ contents = parser.parse()
+ #TODO: change line below when taking from other sources:
+ self.save_page(title + " (from %s)" % wiki, contents, theme, False, True, statuslabel)
+ if statuslabel != None:
+ statuslabel.set_label("Done.")
+# unique=2
+# new_title = title.lower()
+# contents = self.image_handler(parser.parse(), title)
+# if not os.path.exists(os.path.join(self.workingDir, title.lower())):
+# os.makedirs(os.path.join(self.workingDir, title.lower()), 0777)
+# while os.access(os.path.join(self.workingDir, title.lower(), "%s.dita" % new_title), os.F_OK):
+# new_title = title.lower() + str(unique)
+# unique += 1
+# contents = contents.replace('<prolog>', '<prolog>\n<resourceid id="%d" />' % self.get_unique_article_ID(), 1)
+# file = open(os.path.join(self.workingDir, title.lower(), "%s.dita" % new_title), "w")
+# file.write(contents)
+# file.close()
+
+ def get_pages_in_theme(self, theme):
+ """
+ Returns a list of all pages in the specified theme.
+ @param theme: Theme to query
+ @return: List of dictionaries containing page 'path' and 'title'.
+ """
+ try:
+ map = self.load_map(theme)
+ except Exception:
+ return []
+ output = []
+ for page in map.map.findAll("topicref"):
+ output.append(page['navtitle'])
+ output.sort()
+ return output
+
+ def get_themes(self):
+ """
+ Returns a list of all themes stored in the library.
+ @return: List of theme names.
+ """
+ try:
+ map = self.load_map("Library")
+ output = []
+ for theme in map.findAll("topicref"):
+ output.append(theme["navtitle"])
+ output.sort()
+ return output
+ except Exception:
+ return []
+
+ def get_unique_article_ID(self):
+ """
+ Creates and maintains a file to record the last unique article ID issued.
+ when a new ID is requested, returns last id + 1 and upates file.
+ @returns: Unique numeric ID
+ """
+ if not os.access(os.path.join(self.workingDir, "idfile"), os.F_OK):
+ # if no ID file, take a guess at where to start numbering.
+ id = 1
+ # Worst case scenario is that every file is an article, so count all files
+ for item in os.walk(self.workingDir):
+ id += len(item[2])
+ # Multiply by 1000 to prevent any problems caused by deleting files
+ id = id * 1000
+ print "ID FILE NOT FOUND, setting ID to " + str(id)
+ id_file = open(os.path.join(self.workingDir, "idfile"), "w")
+ id_file.write(str(id))
+ id_file.close()
+ return id
+ else:
+ id_file = open(os.path.join(self.workingDir, "idfile"), "r")
+ id = long(id_file.read())
+ id_file.close()
+ id += 1
+ id_file = open(os.path.join(self.workingDir, "idfile"), "w")
+ id_file.write(str(id))
+ id_file.close()
+ return id
+
+ def image_handler(self, document, title, statuslabel=None):
+ """
+ Takes a DITA article and downloads images referenced in it (finding all <image> tags).
+ Attemps to fix incomplete paths using source url.
+ @param document: DITA to work on
+ @param title: Title of article
+ @return: The document with image tags adjusted to point to local paths
+ """
+ document = BeautifulStoneSoup(document)
+ dir_path = os.path.join(self.workingDir, self.clean_title(title), "images")
+ print dir_path
+ if not os.path.exists(dir_path):
+ os.makedirs(dir_path, 0777)
+ if statuslabel != None:
+ i = title.find(" (from ")
+ temptitle = title[0:i]
+ statuslabel.set_label("Downloading %s images..." % (temptitle, ))
+ for image in document.findAll("image"):
+ fail = False
+ path = image['href']
+ if "#DEMOLIBRARY#" in path:
+ path = path.replace("#DEMOLIBRARY#", os.path.join(os.path.split(__file__)[0], "demolibrary"))
+ image_title = os.path.split(path)[1]
+ shutil.copyfile(path, os.path.join(dir_path, image_title))
+ else:
+ image_title = path.rsplit("/", 1)[-1]
+ # attempt to fix incomplete paths
+ if (not path.startswith("http://")) and document.source != None and document.source.has_key("href"):
+ if path.startswith("/"):
+ path = document.source['href'].rsplit("/", 1)[0] + path
+ else:
+ path = document.source['href'].rsplit("/", 1)[0] + "/" + path
+ print "Retrieving image: " + path
+ file = open(os.path.join(dir_path, image_title), 'wb')
+ image_contents = self.__open_URL(path)
+ if image_contents == None:
+ fail = True
+ else:
+ file.write(image_contents)
+ file.close()
+ #change to relative paths:
+ if not fail:
+ image['href'] = os.path.join(dir_path.replace(os.path.join(self.workingDir, ""), "", 1), image_title)
+ else:
+ image.extract()
+ return document.prettify()
+
+ def load_map(self, map_name):
+ """
+ Loads the specified theme map.
+ @param map_name: Name of theme map to load
+ @return: map contents as a Soup
+ @raise theme_not_found_error: If theme map not found.
+ """
+ if not os.access(os.path.join(self.workingDir, "%s.ditamap" % self.clean_title(map_name)), os.F_OK):
+ raise theme_not_found_error("Theme '" + map_name + "' not found")
+ file = open(os.path.join(self.workingDir, "%s.ditamap" % self.clean_title(map_name)), "r")
+ map = BeautifulStoneSoup(file.read())
+ file.close()
+ return map
+
+ def load_raw_page(self, title, theme):
+ """
+ Returns contents of specified page.
+
+ @param title: Title of page to open.
+ @param theme: Theme of page to open.
+ @return: Contents of page.
+ """
+ theme_map = self.load_map(theme)
+ print title + theme
+ page_location = theme_map.find("topicref", attrs={ "navtitle" : title })
+ if page_location != None:
+ page_location = page_location['href']
+ else:
+ raise page_not_found_error("No match for " + title + " in " + theme)
+
+ #if not os.access(page_location, os.F_OK):
+ if os.access(os.path.join(self.workingDir, page_location), os.F_OK):
+ page_location = os.path.join(self.workingDir, page_location)
+ else:
+ raise page_not_found_error("Page not found at " + page_location)
+ page = open(page_location, "r")
+ output = page.read()
+ page.close()
+ return output
+
+ def load_page(self, title, theme):
+ return Article_Builder().get_article_from_dita(self.load_raw_page(title, theme))
+
+ def copy_page(self, title, fromtheme, totheme):
+ """
+ Copys a page from one theme to another. If no title specified, all pages in theme are moved.
+ @param page_title: Title of page to move. (Optional, defaults to None)
+ @param from_theme: Source theme.
+ @param to_theme: Destination theme.
+ """
+ print "COPY PAGE %s FROM %s TO %s" % (title, fromtheme, totheme)
+ article = self.load_raw_page(title, fromtheme)
+ self.save_page(title, article, totheme, overwrite=False)
+
+ def load_article(self, title, theme):
+ """
+ loads the specified article
+ """
+ article_data = self.load_page(title, theme)
+ article = Article(article_data)
+ article.article_title = title
+ article.article_theme = theme
+ return article
+
+ def move_page(self, from_theme, to_theme, page_title = None):
+ """
+ Moves a page from one theme to another. If no title specified, all pages in theme are moved.
+ @param page_title: Title of page to move. (Optional, defaults to None)
+ @param from_theme: Source theme.
+ @param to_theme: Destination theme.
+ """
+ try:
+ from_map = self.load_map(from_theme)
+ to_map = self.load_map(to_theme)
+ if page_title == None:
+ pages = from_map.findAll("topicref")
+ else:
+ pages = [from_map.find("topicref", attrs={"navtitle" : page_title})]
+ if pages == [None] or pages == []:
+ raise exception("not found")
+ for page in pages:
+ to_map.map.append(page)
+ self.save_map(to_theme, to_map)
+ for page in pages:
+ page.extract()
+ self.save_map(from_theme, from_map)
+ except Exception:
+ # Shouldn't ever happen
+ pass
+
+ def __open_URL(self, url):
+ """
+ retrieves content from specified url
+ """
+ urllib._urlopener = self.New_URL_Opener()
+ try:
+ print "opening " + url
+ print "proxies: " + str(self.proxies)
+ doc = urllib.urlopen(url, proxies=self.proxies)
+ output = doc.read()
+ doc.close()
+ print "url opened succesfully"
+ return output
+ except IOError, e:
+ print e
+
+ def page_exists(self, title, theme):
+ """
+ boolean check if an article exists
+ """
+ try:
+ map = self.load_map(theme)
+ if map.find("topicref", attrs={"navtitle" : title}) != None:
+ return True
+ else:
+ return False
+ except Exception:
+ return False
+
+ def theme_exists(self, theme):
+ """
+ boolean check if a theme exists
+ """
+ themes = self.get_themes()
+ if theme in themes:
+ return True
+ else:
+ return False
+
+ def remove_page(self, page, theme):
+ """
+ Removes specified page from the specified theme.
+ @param page: Page to remove
+ @param theme: Containing theme
+ """
+ if theme == "Downloaded Articles":
+ return
+ theme_map = self.load_map(theme)
+ entry = theme_map.find("topicref", attrs={"navtitle" : page})
+ try:
+ os.remove(entry['href'])
+ except Exception:
+ pass
+ entry.extract()
+ self.save_map(theme, theme_map)
+
+ def remove_theme(self, theme):
+ """
+ Removes specified theme, moving all articles in it to the 'No Assigned Theme' theme.
+ @param theme: Theme to remove
+ """
+ try:
+ #Just remove map from library at the moment
+ #self.move_pages(theme, "No Assigned Theme")
+ library = self.load_map("Library")
+ entry = library.find("topicref", attrs={"navtitle" : theme})
+ if entry != None:
+ os.remove(os.path.join(self.workingDir, entry['href']))
+ entry.extract()
+ self.save_map("Library", library)
+ except Exception:
+ # Trying to remove a theme that doesn't exist, so pretend it worked.
+ pass
+
+ def rename_page(self, theme, old_title, new_title):
+ """
+ renames specified page in specified theme
+ """
+ try:
+ map = self.load_map(theme)
+ page = map.find("topicref", attrs={"navtitle" : old_title})
+ if page != None:
+ page['navtitle'] = new_title
+ self.save_map(theme, map)
+ except Exception:
+ pass
+
+ def rename_theme(self, old_name, new_name):
+ """
+ renames specified theme
+ """
+ library = self.load_map("Library")
+ entry = library.find("topicref", attrs={"navtitle" : old_name})
+ if entry != None and library.find("topicref", attrs={"navtitle" : new_name}) == None:
+ self.add_theme_to_library(new_name)
+ theme = self.load_map(entry['navtitle'])
+ theme.map['name'] = new_name
+ self.save_map(new_name, theme)
+ self.remove_theme(old_name)
+
+ def save_article(self, article, overwrite = True):
+ """
+ wrapper method for save_page to allow saving article objects
+ """
+ title = article.article_title
+ theme = article.article_theme
+ if title != None and theme != None:
+ contents = Article_Builder().get_dita_from_article(article)
+ self.save_page(title, contents, theme, overwrite)
+ else:
+ raise theme_not_found_error("Theme or title not specified")
+
+ def save_map(self, map_name, map_data):
+ """
+ Saves the specified map.
+ @param map_name: Name of map
+ @param map_data: Contents of map
+ """
+ if not os.path.exists(self.workingDir):
+ os.makedirs(self.workingDir, 0777)
+ map = open(os.path.join(self.workingDir, "%s.ditamap" % self.clean_title(map_name)), "w")
+ map.write(map_data.prettify())
+ map.close()
+
+ def save_page(self, title, contents, theme="Downloaded Articles", overwrite=True, get_images=False, statuslabel=None):
+ """
+ Saves the specified page contents as specified title (in optional specified theme).
+ @param title: Title to save as.
+ @param contents: Contents to save.
+ @param theme: Theme to save in.
+ @param overwrite: Boolean to specify overwrite if file already exists.
+ """
+ unique=2
+ new_title = self.clean_title(title) + "-" + self.clean_title(theme)
+ if get_images:
+ contents = self.image_handler(contents, title, statuslabel)
+ directory = os.path.join(self.workingDir, self.clean_title(title))
+ if not os.path.exists(directory):
+ os.makedirs(directory, 0777)
+ if overwrite == False:
+ while os.access(os.path.join(directory, "%s.dita" % new_title), os.F_OK):
+ new_title = self.clean_title(title) + str(unique)
+ unique += 1
+ contents = contents.replace('<prolog>', '<prolog>\n<resourceid id="%d" />' % self.get_unique_article_ID(), 1)
+ file = open(os.path.join(directory, "%s.dita" % new_title), "w")
+ file.write(contents)
+ file.close()
+ self.__add_page_to_library(title, os.path.join(directory, "%s.dita" % new_title), theme)
+ print "Page saved to - " + os.path.join(directory, "%s.dita" % new_title)
+ return os.path.join(directory, "%s.dita" % new_title)
+
+ def validate_image_list(self, image_list):
+ """
+ provides a mechanism for validating image lists and expanding relative paths
+ @param image_list: list of images to validate
+ @return: list of images with corrected paths, and broken images removed
+ """
+ for i in xrange(len(image_list)):
+ if not os.access(image_list[i][0], os.F_OK):
+ if os.access(os.path.join(self.workingDir, image_list[i][0]), os.F_OK):
+ image_list[i] = (os.path.join(self.workingDir, image_list[i][0]), image_list[i][1])
+ else:
+ image = None
+ #removing during for loop was unreliable
+ while None in image_list:
+ image_list.remove(None)
+ return image_list
+
+ class New_URL_Opener(urllib.FancyURLopener):
+ version = "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11" \ No newline at end of file
diff --git a/Processing/MediaWiki_Helper.py b/Processing/MediaWiki_Helper.py
new file mode 100644
index 0000000..3a328f3
--- /dev/null
+++ b/Processing/MediaWiki_Helper.py
@@ -0,0 +1,263 @@
+# Copyright (C) IBM Corporation 2008
+
+import urllib
+import IO_Manager
+from xml.dom import minidom
+
+"""
+Extend urllib class to spoof user-agent
+"""
+class NewURLopener(urllib.FancyURLopener):
+ version = "Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11"
+
+class PageNotFoundError(Exception):
+ def __init__(self, value):
+ self.parameter = value
+ def __str__(self):
+ return repr(self.parameter)
+
+class NoResultsError(Exception):
+ def __init__(self, value):
+ self.parameter = value
+ def __str__(self):
+ return repr(self.parameter)
+
+"""
+Default media wikihost
+"""
+defaultWiki = "en.wikipedia.org"
+
+
+"""
+This class handles interaction with Media Wiki. Getting
+content based on a number of parameters such as URL, Title, Revision.
+"""
+class MediaWiki_Helper:
+
+ def __init__(self):
+ self.proxies = IO_Manager.IO_Manager().proxies
+
+ def resolveTitle(self, title, wiki=defaultWiki):
+ """Check if a wiki article exists using the mediawiki api. Follow redirects.
+
+ @param title: article title to resolve
+ @param wiki: optional. Defaults to default wiki
+ @return: validated article title
+ @rtype: string
+ @raise PageNotFoundError: if page not found"""
+ #replace spaces with underscores
+ title = title.replace(" ", "_")
+ #create the API request string
+ path = "http://%s/w/api.php?action=query&titles=%s&redirects&format=xml" % (wiki, title)
+ #parse the xml
+ xmldoc = minidom.parseString(self.getDoc(path))
+ #check page exists, return None if it doesn't
+ page = xmldoc.getElementsByTagName("page")
+ if (page != []):
+ if ("missing" in page[0].attributes.keys()):
+ raise PageNotFoundError("The article with title '%s' could not be found on wiki '%s'" % (title, wiki))
+ #check if there are any redirection tags defined
+ redirectList = xmldoc.getElementsByTagName("r")
+ #if the redirect list is empty, return the title
+ if redirectList == []:
+ return title
+ #if there is a redirect, recursively follow the chain
+ else:
+ return self.resolveTitle(redirectList[0].attributes["to"].value)
+
+ def resolveRevision(self, revision, wiki=defaultWiki):
+ """ get an article by revision number.
+
+ @param revision: revision number to resolve
+ @param wiki: optional. Defaults to default wiki
+ @return: revision number if valid
+ @rtype: string
+ @raise PageNotFoundError: if page not found"""
+ path = "http://%s/w/api.php?action=query&format=xml&revids=%s" % (wiki, revision)
+ if ("page" in self.getDoc(path)):
+ return revision
+ else:
+ raise PageNotFoundError("The article with revision id '%s' could not be found on wiki '%s'" % (revision, wiki))
+
+ def getArticleAsWikiTextByTitle(self, title, wiki=defaultWiki):
+ """Gets the wiki markup of an article by its title from the wiki specified.
+
+ @param title: title of article to retrieve
+ @param wiki: optional. Defaults to default wiki
+ @return: article content in wiki markup
+ @rtype: string"""
+ #resolve the article title
+ title = self.resolveTitle(title)
+ #create the API request string
+ path = "http://%s/w/api.php?action=query&prop=revisions&titles=%s&rvprop=content&format=xml" % (wiki, title)
+ #remove xml tags around article
+ return self.stripTags(getDoc(path), "rev")
+
+ def getArticleAsWikiTextByURL(self, url):
+ """Gets the wiki markup of an article by its title from the wiki specified.
+
+ @param url: url of article to retrieve
+ @param wiki: optional. Defaults to default wiki
+ @return: article content in wiki markup
+ @rtype: string"""
+ args = self.breakdownURL(url)
+ if len(args) == 3:
+ return self.getArticleAsWikiTextByRevision(args[2], args[0])
+ else:
+ return self.getArticleAsWikiTextByTitle(args[1], args[0])
+
+ def getArticleAsWikiTextByRevision(self, revision, wiki=defaultWiki):
+ """Gets the wiki markup of an article by its revision id from the wiki specified.
+
+ @param revision: revision id of article to retrieve
+ @param wiki: optional. Defaults to default wiki
+ @return: article content in wiki markup
+ @rtype: string"""
+ self.resolveRevision(revision, wiki)
+ path = "http://%s/w/api.php?action=query&prop=revisions&revids=%s&rvprop=content&format=xml" % (wiki, revision)
+ return self.stripTags(getDoc(path), "rev")
+
+ def getArticleAsHTMLByTitle(self, title, wiki=defaultWiki):
+ """Gets the HTML markup of an article by its title from the wiki specified.
+
+ @param title: title of article to retrieve
+ @param wiki: optional. Defaults to default wiki
+ @return: article content in HTML markup
+ @rtype: string"""
+ #resolve article title
+ title = self.resolveTitle(title, wiki)
+ #create the API request string
+ path = "http://%s/w/api.php?action=parse&page=%s&format=xml" % (wiki,title)
+ #remove xml tags around article and fix HTML tags and quotes
+ #return fixHTML(stripTags(getDoc(path), "text"))
+ return self.fixHTML(self.getDoc(path)), path
+
+ def getArticleAsHTMLByURL(self, url):
+ """Gets the HTML markup of an article by its title from the wiki specified.
+
+ @param url: url of article to retrieve
+ @param wiki: optional. Defaults to default wiki
+ @return: article content in HTML markup
+ @rtype: string"""
+ args = self.breakdownURL(url)
+ if len(args) == 3:
+ return self.getArticleAsHTMLByRevision(args[2], args[0])
+ else:
+ return self.getArticleAsHTMLByTitle(args[1], args[0])
+
+ def getArticleAsHTMLByRevision(self, revision, wiki=defaultWiki):
+ """Gets the HTML markup of an article by its revision id from the wiki specified.
+
+ @param revision: revision id of article to retrieve
+ @param wiki: optional. Defaults to default wiki
+ @return: article content in HTML markup
+ @rtype: string"""
+ self.resolveRevision(revision, wiki)
+ path = "http://%s/w/api.php?action=parse&oldid=%s&format=xml" % (wiki,revision)
+ #remove xml tags around article and fix HTML tags and quotes
+ return self.fixHTML(stripTags(getDoc(path), "text"))
+
+ def breakdownURL(self, url):
+ """pulls out wiki address, title and revision id from a wiki URL
+
+ @param url: url to process
+ @return: information from url
+ @rtype: list"""
+ outputlist = []
+ url = url.replace("http://", "")
+ outputlist.append(url.split("/")[0])
+ if ("title=" in url):
+ outputlist.append(url.split("title=")[-1].split("&")[0])
+ if ("oldid=" in url):
+ outputlist.append(url.split("oldid=")[-1].split("&")[0])
+ else:
+ outputlist.append(url.split("/")[-1])
+ return outputlist
+
+ def getDoc(self, path):
+ """opens a remote file by http and retrieves data
+
+ @param path: location of remote file
+ @return: page contents
+ @rtype: string"""
+ urllib._urlopener = NewURLopener()
+ print "opening " + path
+ print "proxies: " + str(self.proxies)
+ doc = urllib.urlopen(path, proxies=self.proxies)
+ output = doc.read()
+ doc.close()
+ print "url opened successfully"
+ return output
+
+ def stripTags(self, input, tag):
+ """removes specified tag
+
+ @param input: string to work on
+ @param tag: tag to remove
+ @return: original string with specified tag removed
+ @rtype: string"""
+ return input.split("<%s>" % (tag), 1)[1].split("</%s>" % (tag), 1)[0]
+
+ def fixHTML(self, input):
+ """fixes <, > and " characters in HTML
+
+ @param input: input string to work on
+ @return: modified version of input
+ @rtype: string"""
+ return input.replace("&lt;", "<").replace("&gt;", ">").replace("&quot;",'"')
+
+ def getImageURLs(self, title, wiki=defaultWiki, revision=None):
+ """returns a list of the URLs of every image on the specified page on the (optional) specified wiki
+ @deprecated: This task is now performed at the parsing stage
+ """
+ #check article title is valid, follow redirects
+ title = self.resolveTitle(title, wiki)
+ #proceed if title is valid
+ if (title != None):
+ #create the API request string
+ path = "http://%s/w/api.php?action=query&prop=images&titles=%s&format=xml" % (wiki, title)
+ xmldoc = minidom.parseString(self.getDoc(path))
+ imglist = xmldoc.getElementsByTagName("im")
+ outputlist = []
+ for i in xrange(len(imglist)):
+ #create the API request string
+ path = "http://%s/w/api.php?action=query&titles=%s&prop=imageinfo&iiprop=url&format=xml" % (wiki, imglist[i].attributes["title"].value.replace(" ","_"))
+ xmldoc2 = minidom.parseString(self.getDoc(path))
+ #append image url to output
+ outputlist.append(xmldoc2.getElementsByTagName("ii")[0].attributes["url"].value)
+ #return outputlist
+ return []
+
+ def getImages(self, title, wiki=defaultWiki):
+ """returns a list of the URLs of every image on the specified page on the (optional) specified wiki
+ @deprecated: This task is now performed at the saving stage
+ """
+ imglist = getImageURLs(title, wiki)
+ outputlist = []
+ if imglist !=[]:
+ for i in imglist:
+ outputlist.append(getDoc(i))
+ return outputlist
+
+ def searchWiki(self, search, wiki=defaultWiki):
+ """Search a wiki using the openSearch protocol.
+
+ @param search: string to search for
+ @param wiki: optional. Defaults to default wiki
+ @return: search results and description pairs
+ @rtype: list"""
+ path = "http://%s/w/api.php?action=opensearch&search=%s&format=xml" % (wiki, search)
+ output = minidom.parseString(self.getDoc(path))
+ results = []
+ for item in output.getElementsByTagName("Item"):
+ results.append((item.getElementsByTagName("Text")[0].firstChild.data, item.getElementsByTagName("Description")[0].firstChild.data))
+ return results
+
+ # TODO: make this work with new searchWiki method
+ """def getFirstSearchResult(search, wiki=defaultWiki):
+ xmldoc = minidom.parseString(searchWiki(search, wiki))
+ resultList = xmldoc.getElementsByTagName("Item")
+ if (len(resultList) > 0):
+ return stripTags(resultList[0].getElementsByTagName("Text")[0].toxml(), "Text")
+ else:
+ raise noResultsError("No results found for '%s' on wiki: %s" % (search, wiki))""" \ No newline at end of file
diff --git a/Processing/MediaWiki_Parser.py b/Processing/MediaWiki_Parser.py
new file mode 100644
index 0000000..cf57b40
--- /dev/null
+++ b/Processing/MediaWiki_Parser.py
@@ -0,0 +1,79 @@
+# Copyright (C) IBM Corporation 2008
+
+from HTML_Parser import HTML_Parser
+import re
+
+class MediaWiki_Parser(HTML_Parser):
+
+ #Overwriting the regexp so that various non-data content (see also, table of contents etc.) is removed
+ remove_classes_regexp = re.compile("toc|noprint|metadata|sisterproject|boilerplate|reference(?!s)|thumb|navbox|editsection")
+
+ def __init__(self, document_to_parse, title, source_url):
+ if input == None:
+ raise NoDocException("No content to parse - supply document to __init__")
+ #find the revision id in the xml the wiki API returns
+ revid = re.findall(re.compile('\<parse revid\=\"(?P<rid>[0-9]*)\">'), document_to_parse)
+ #remove the xml padding to parse html inside
+ input_content = document_to_parse.split("<text>")[1]
+ input_content = input_content.split("</text>")[0]
+ #call the normal constructor
+ HTML_Parser.__init__(self, "<body>" + input_content + "</body>", title, source_url)
+ #overwrite the source variable
+ self.source = "http://" + source_url.replace("http://", "").split("/")[0] + "/w/index.php?oldid=%s" % revid[0]
+
+ def specialise(self):
+ """
+ Uses DITA_Parser class's specialise() call to find the infobox in a wiki article
+ """
+ #infobox should be first table
+ first_table = self.input.find("table")
+ #the word "infobox" should be in the class name somewhere
+ if (first_table != None and first_table.has_key("class") and (re.match(re.compile("infobox"), first_table["class"]) != None)):
+ #make a new output tag to work with
+ infobox_tag = self.tag_generator("section", attrs=[("id", "infobox")])
+ #sometimes infobox data is in an inner table
+ inner_table = first_table.table
+ #sometimes it isn't :-(
+ if inner_table == None:
+ #if there isn't an inner table, work on the outer table
+ inner_table = first_table
+ # the title _should_ be in a "colspan == 2" tag
+ inner_table_title = first_table.find(attrs={ "colspan" : "2"})
+ #don't break if title can't be found
+ if inner_table_title != None:
+ #get the title
+ inner_table_title_temp = inner_table_title.renderContents()
+ #remove the title so it isn't processed twice
+ inner_table_title.extract()
+ inner_table_title = inner_table_title_temp
+ else:
+ # if there is an inner table, the title will be in the containing table - hunt it down.
+ inner_table_title = inner_table.findParent("tr").findPreviousSibling("tr").findChild("th").renderContents()
+ #finally append the title to the tag
+ infobox_tag.append(self.tag_generator("title", inner_table_title))
+ #generate the properties list
+ properties_tag = self.tag_generator("properties")
+ infobox_tag.append(properties_tag)
+ #each property is a row in the table
+ for tr in inner_table.findAll("tr"):
+ #make sure the row isn't empty
+ if tr.findChild() != None:
+ #make a new <property> tag
+ property_tag = self.tag_generator("property")
+ #table cells are either th or td
+ table_cells = tr.findAll(re.compile("th|td"))
+ if len(table_cells) == 0:
+ pass
+ elif len(table_cells) == 1:
+ #if there's only one cell on the row, make it a value
+ property_tag.append(self.tag_generator("propvalue", table_cells[0].renderContents()))
+ else:
+ #if there are two cells on the row, the first is the property type, the second is the value
+ property_tag.append(self.tag_generator("proptype", table_cells[0].renderContents().replace(":", "")))
+ property_tag.append(self.tag_generator("propvalue", table_cells[1].renderContents()))
+ #add the property to the <properties> tag
+ properties_tag.append(property_tag)
+ #add the infobox to the output
+ self.output_soup.refbody.append(infobox_tag)
+ #remove the first table to avoid parsing twice
+ first_table.extract() \ No newline at end of file
diff --git a/Processing/NewtifulSoup.py b/Processing/NewtifulSoup.py
new file mode 100644
index 0000000..4e26a12
--- /dev/null
+++ b/Processing/NewtifulSoup.py
@@ -0,0 +1,9 @@
+# Copyright (C) IBM Corporation 2008
+
+from BeautifulSoup import BeautifulStoneSoup
+
+#Extend beautiful soup HTML parsing library
+#to recognise new self-closing tag <reference>
+class NewtifulStoneSoup(BeautifulStoneSoup):
+ NESTABLE_TAGS = BeautifulStoneSoup.NESTABLE_TAGS
+ NESTABLE_TAGS['reference'] = 'reference' \ No newline at end of file
diff --git a/Processing/Package_Creator.py b/Processing/Package_Creator.py
new file mode 100644
index 0000000..abbfa84
--- /dev/null
+++ b/Processing/Package_Creator.py
@@ -0,0 +1,229 @@
+# Copyright (C) IBM Corporation 2008
+
+import os, platform, zipfile, shutil, re
+from IO_Manager import IO_Manager
+from NewtifulSoup import NewtifulStoneSoup as BeautifulStoneSoup
+
+class Package_Creator:
+ """
+ @author: Matthew Bailey
+
+ This class deals with the creation of content packages, comprised of articles from
+ themes, with are zipped up and installed in the relevant OS specific location. From
+ here they can be distributed to the consumers
+ """
+
+ """
+ Copy articles from library into new content theme (themename) and package up (filename).
+ """
+ def __init__(self, articlestocopy, themename, filename, package_type, caller=None):
+ """
+ Grab file's parent directory and create temporary directory structure for content
+ """
+ self.currentdir = os.path.split(__file__)[0]
+ self.make_directories(themename)
+ if package_type == 'xol':
+ self.info_file(themename)
+ self.index_redirect(themename, package_type)
+
+ self.dita_management(articlestocopy, themename)
+
+ self.copy_stylesheets(themename)
+ self.create_bundle(themename, filename)
+
+ running_on = platform.system()
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ already_exists = self.copy_to_journal(themename)
+ if already_exists == True:
+ caller.export_message.set_text('A bundle by that name already exists. Please click "Erase" in the Journal. You can click \'Publish\' again afterwards.')
+ elif already_exists == False:
+ caller.export_message.set_text('Your bundle has been created and will appear in the Journal. You can also create another.')
+ else:
+ caller.export_message.set_text('We\'re sorry, but something appears to have gone wrong with bundle creation.')
+
+ """
+ Remove temporary files
+ """
+ self.remove_directories(themename)
+
+ def copy_stylesheets(self, themename):
+ """
+ Copies the XSL and CSS stylesheets into the slicecontent folder
+ @param themename: the name of the theme that is being exported
+ """
+ themeloc = themename.replace(" ", "_")
+ shutil.copyfile('%s/../Stylesheets/ditastylesheet.xsl' % self.currentdir, '%s/%s/slicecontent/ditastylesheet.xsl' % (IO_Manager().workingDir, themeloc))
+ shutil.copyfile('%s/../Stylesheets/mapstylesheet.xsl' % self.currentdir, '%s/%s/slicecontent/mapstylesheet.xsl' % (IO_Manager().workingDir, themeloc))
+ shutil.copyfile('%s/../Stylesheets/ditastyle.css' % self.currentdir, '%s/%s/slicecontent/ditastyle.css' % (IO_Manager().workingDir, themeloc))
+ shutil.copyfile('%s/../Stylesheets/mapstyle.css' % self.currentdir, '%s/%s/slicecontent/mapstyle.css' % (IO_Manager().workingDir, themeloc))
+
+ def create_bundle(self, themename, filename):
+ """
+ Creates the xol package and writes the files and directories to the zip
+ @param themename: the name of the theme that is being exported
+ """
+ themeloc = themename.replace(" ", "_")
+ running_on = platform.system()
+ if running_on == "Linux" and "olpc" in platform.platform().lower():
+ zip = zipfile.ZipFile('%s/%s.xol' % (IO_Manager().workingDir, themeloc), 'w')
+ else:
+ zip = zipfile.ZipFile(filename, 'w')
+ self.zipdir('%s/library/' % themeloc, zip)
+ self.zipdir('%s/slicecontent/' % themeloc, zip)
+ zip.write('%s/%s/index.html' % (IO_Manager().workingDir, themeloc), '%s/index.html' % themeloc)
+ zip.close()
+
+ def copy_to_journal(self, themename):
+ """
+ Copies the xol package to the journal, which can then be copied to a USB drive, etc. and also makes content visible in the browser
+ @param themename: the name of the theme that is being exported
+ """
+ from sugar.datastore import datastore
+ from sugar import activity
+# from sugar.bundle.contentbundle import ContentBundle
+ journal_listing = datastore.find({'title':themename, 'mime_type':'application/vnd.olpc-content'})
+# for id in journal_listing[0]:
+# test = ContentBundle('/home/olpc/.sugar/default/data/%s.xol' % id.object_id)
+# test.uninstall()
+# datastore.delete(id.object_id)
+ if not journal_listing[0]:
+ themeloc = themename.replace(" ", "_")
+ journal_entry = datastore.create()
+ activityinfo_list = activity.get_registry().find_activity("Browse")
+# for activityinfo in activityinfo_list:
+# if activityinfo.name == "Browse":
+# bid = activityinfo.bundle_id
+ journal_entry.set_file_path('%s/%s.xol' % (IO_Manager().workingDir, themeloc))
+ journal_entry.metadata['title'] = '%s' % themename
+# journal_entry.metadata['activity'] = bid
+# journal_entry.metadata['uri'] = 'file:///home/olpc/.library_pages/search/bundle_index.html'
+ journal_entry.metadata['mime_type'] = 'application/vnd.olpc-content'
+ journal_entry.metadata['description'] = 'This is a bundle containing articles on %s.\nTo view these articles, first open '\
+ 'the \'Browse\' Activity.\nGo to \'Books\', and select \'%s\'.' % (themename, themename)
+ datastore.write(journal_entry)
+ journal_entry.destroy()
+ return False
+ elif journal_listing[0]:
+ return True
+
+ def dita_management(self, articlestocopy, themename):
+ """
+ Creates a DITA map, and copies the requested articles and their associated images into the zipped directories
+ @param articlestocopy: a list of articles to copy
+ @param themename: the name of the theme that is being exported
+ """
+ newmap = ['<?xml version=\'1.0\' encoding=\'utf-8\'?>',\
+ '<!DOCTYPE map PUBLIC "-//IBM//DTD DITA IBM Map//EN" "ibm-map.dtd">',\
+ '<?xml-stylesheet type="text/xsl" href="mapstylesheet.xsl"?>',\
+ '<map title="%s">' % themename]
+
+ current_dita_map = IO_Manager().load_map(themename)
+ themeloc = themename.replace(" ", "_")
+
+ for articlename in articlestocopy:
+ articletitle = articlename
+ articleloc = current_dita_map.find('topicref', attrs={"navtitle":articlename})['href']
+ article = IO_Manager().load_raw_page(articlename, themename)
+ #Inserted line above, because line below no longer works due to filename changes
+ #article = self.open_article(articleloc.lower())
+ self.articlecontent = BeautifulStoneSoup(article)
+ for image in self.articlecontent.findAll('image'):
+ imageloc = image['href'].replace("..", IO_Manager().workingDir)
+ imagename = os.path.split(imageloc)[-1]
+ imagename = imagename.replace("%","")
+ shutil.copyfile('%s' % (imageloc), '%s/%s/slicecontent/%s' % (IO_Manager().workingDir, themeloc, imagename))
+ image['href'] = imagename
+ self.articlecontent.insert(1, '<?xml-stylesheet type="text/xsl" href="ditastylesheet.xsl"?>')
+ article = open('%s/%s/slicecontent/%s.dita' % (IO_Manager().workingDir, themeloc, IO_Manager().clean_title(articlename)), 'w')
+ article.write(self.articlecontent.prettify())
+ newmap.append('\t<topicref href="%s.dita" navtitle="%s">' % (IO_Manager().clean_title(articlename), articletitle))
+ newmap.append('\t</topicref>')
+ newmap.append('</map>')
+ ditamap = open('%s/%s/slicecontent/librarymap.ditamap' % (IO_Manager().workingDir, themeloc), 'w')
+ ditamap.write("\n".join(newmap))
+
+ def index_redirect(self, themename, package_type):
+ """
+ Creates the redirecting index.html
+ @param themename: the name of the theme that is being exported
+ @param package_type: the type of package (e.g. 'zip' or 'xol') that is being created
+ """
+ themeloc = themename.replace(" ", "_")
+ if package_type == 'xol':
+ redirect_loc = '/home/olpc/Library/%s/slicecontent/librarymap.ditamap' % themeloc
+ elif package_type == 'zip':
+ redirect_loc = 'slicecontent/librarymap.ditamap'
+ html = ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">',\
+ '<html>',\
+ '<head>',\
+ '<title>Redirecting to index</title>',\
+ '<meta http-equiv="REFRESH" content="0;url=%s">' % redirect_loc,\
+ '</head>',\
+ '<body>',\
+ '</body>',\
+ '</html>']
+
+ htmlfile = open('%s/%s/index.html' % (IO_Manager().workingDir, themeloc), 'w')
+ htmlfile.write("\n".join(html))
+
+ def info_file(self, themename):
+ """
+ Creates the library.info file
+ @param themename: the name of the theme that is being exported
+ """
+ themeloc = themename.replace(" ", "_")
+ libraryfile = ['[Library]',\
+ 'name = %s' % themeloc,\
+ 'global_name = info.slice.%s' % themename.lower(),\
+ 'long_name = %s' % themename,\
+ 'library_version = 1',\
+ 'host_version = 1',\
+ 'l10n = false',\
+ 'locale = en',\
+ 'category = books',\
+ 'subcategory = slice',\
+ 'icon = book.png',\
+ 'activity = Web',\
+ 'activity_start = index.html']
+
+ infofile = open('%s/%s/library/library.info' % (IO_Manager().workingDir, themeloc), 'w')
+ infofile.write("\n".join(libraryfile))
+
+ def make_directories(self, themename):
+ """
+ Creates the directories that will be zipped
+ @param themename: the name of the theme that is being exported
+ """
+ themename = themename.replace(" ", "_")
+ if os.path.exists("%s/%s" % (IO_Manager().workingDir, themename)):
+ shutil.rmtree("%s/%s" % (IO_Manager().workingDir, themename))
+ os.mkdir('%s/%s' % (IO_Manager().workingDir, themename))
+ os.mkdir('%s/%s/library' % (IO_Manager().workingDir, themename))
+ os.mkdir('%s/%s/slicecontent' % (IO_Manager().workingDir, themename))
+
+ def open_article(self, articleloc):
+ """
+ Opens the relevant DITA file and returns it as a string
+ @param articleloc: the location of the DITA file to be opened
+ @return: a string containing the contents of the DITA file
+ """
+ file = open('%s' % (articleloc), 'r').read()
+ return file
+
+ def remove_directories(self, themename):
+ """
+ Removes the directories created on the filesystem for the zip
+ @param themename: the name of the theme that is being exported
+ """
+ themename = themename.replace(" ", "_")
+ shutil.rmtree("%s/%s" % (IO_Manager().workingDir, themename))
+
+ def zipdir(self, path, zip):
+ """
+ Writes directories and their contents to the zip
+ @param path: the path of the directory that is to be zipped
+ @param zip: the variable name of the zip that is to be written to
+ """
+ fullpath = '%s/%s' % (IO_Manager().workingDir, path)
+ for each in os.listdir(fullpath):
+ zip.write(fullpath + each, path + each) \ No newline at end of file
diff --git a/Processing/__init__.py b/Processing/__init__.py
new file mode 100644
index 0000000..1bc63d4
--- /dev/null
+++ b/Processing/__init__.py
@@ -0,0 +1,3 @@
+# Copyright (C) IBM Corporation 2008
+
+# This file should exist, despite having no code in it
diff --git a/Processing/demolibrary/giraffe-blank.dita b/Processing/demolibrary/giraffe-blank.dita
new file mode 100644
index 0000000..3014c58
--- /dev/null
+++ b/Processing/demolibrary/giraffe-blank.dita
@@ -0,0 +1,10 @@
+<!-- Copyright (C) IBM Corporation 2008 -->
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE reference PUBLIC "-//IBM//DTD DITA IBM Reference//EN" "ibm-reference.dtd">
+<reference>
+ <title>
+ Giraffe
+ </title>
+ <prolog>
+ </prolog>
+</reference> \ No newline at end of file
diff --git a/Processing/demolibrary/giraffe-wikipedia.dita b/Processing/demolibrary/giraffe-wikipedia.dita
new file mode 100644
index 0000000..ff1ba20
--- /dev/null
+++ b/Processing/demolibrary/giraffe-wikipedia.dita
@@ -0,0 +1,968 @@
+<?xml version='1.0' encoding='utf-8'?>
+<reference>
+ <title>
+ Giraffe
+ </title>
+ <shortdesc>
+ <ph id="2">
+ The giraffe (Giraffa camelopardalis) is an African even-toed ungulate mammal, the tallest of all land-living animal species, and the largest ruminant.
+ </ph>
+ <ph id="3">
+ Males can be 4.8 to 5.5&amp;#160;metres (16 to 18 feet) tall and weigh up to 1,700&amp;#160;kilograms (3,800&amp;#160;pounds).
+ </ph>
+ <ph id="4">
+ The record-sized bull, shot in Kenya in 1934, was 5.87&amp;#160;m (19.2&amp;#160;ft) tall and weighed approximately 2,000&amp;#160;kg (4,400&amp;#160;lb).
+ </ph>
+ <ph id="5">
+ Females are generally slightly shorter, and weigh less than the males do.
+ </ph>
+ </shortdesc>
+ <prolog>
+ <source href="http://en.wikipedia.org/w/index.php?oldid=235433231">
+ <publisher>
+ wikipedia.org
+ </publisher>
+ <critdates>
+ <created date="2008-09-05">
+ <revised modified="2008-09-05">
+ </revised>
+ </created>
+ </critdates>
+ </source>
+ </prolog>
+ <refbody>
+ <section id="infobox">
+ <title>
+ Scientific classification
+ </title>
+ <properties>
+ <property>
+ <proptype>
+ Kingdom
+ </proptype>
+ <propvalue>
+ Animalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Phylum
+ </proptype>
+ <propvalue>
+ Chordata
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Class
+ </proptype>
+ <propvalue>
+ Mammalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Order
+ </proptype>
+ <propvalue>
+ Artiodactyla
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Family
+ </proptype>
+ <propvalue>
+ Giraffidae
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Genus
+ </proptype>
+ <propvalue>
+ Giraffa
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Species
+ </proptype>
+ <propvalue>
+ G. camelopardalis
+ </propvalue>
+ </property>
+ </properties>
+ </section>
+ <p id="2">
+ <ph id="6">
+ The giraffe is related to deer and cattle, but is placed in a separate family, the Giraffidae, consisting only of the giraffe and its closest relative, the okapi.
+ </ph>
+ <ph id="7">
+ Its range extends from Chad to South Africa.
+ </ph>
+ </p>
+ <p id="3">
+ <ph id="8">
+ Giraffes can inhabit savannas, grasslands, or open woodlands.
+ </ph>
+ <ph id="9">
+ They prefer areas enriched with acacia growth.
+ </ph>
+ <ph id="10">
+ They drink large quantities of water and, as a result, they can spend long periods of time in dry, arid areas.
+ </ph>
+ <ph id="11">
+ When searching for more food they will venture into areas with denser foliage.
+ </ph>
+ </p>
+ <p id="4">
+ <ph id="12">
+ </ph>
+ </p>
+ </refbody>
+ <reference id="2">
+ <title>
+ Etymology
+ </title>
+ <refbody>
+ <p id="5">
+ <ph id="13">
+ The species name camelopardalis (camelopard) is derived from its early Roman name, where it was described as having characteristics of both a camel and a leopard.
+ </ph>
+ <ph id="14">
+ The English word camelopard first appeared in the 14th century and survived in common usage well into the 19th century.
+ </ph>
+ <ph id="15">
+ The Afrikaans language retained it.
+ </ph>
+ <ph id="16">
+ The Arabic word الزرافة ziraafa or zurapha, meaning "assemblage"
+ </ph>
+ <ph id="17">
+ (of animals), or just "tall", was used in English from the sixteenth century on, often in the Italianate form giraffa.
+ </ph>
+ </p>
+ <p id="6">
+ <ph id="18">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="3">
+ <title>
+ Taxonomy and evolution
+ </title>
+ <refbody>
+ <p id="7">
+ <ph id="19">
+ Giraffids evolved from a 3&amp;#160;metre (10&amp;#160;ft) tall antelope-like mammal which roamed Europe and Asia 30-50 million years ago.
+ </ph>
+ <ph id="20">
+ The earliest giraffid was the Climacoceras, which still resembled deer, having large antler-like ossicones.
+ </ph>
+ <ph id="21">
+ It first appeared in the early Miocene period.
+ </ph>
+ <ph id="22">
+ As the lineage went on the genuses Palaeotragus and Samotherium appeared in the early to mid-Miocene.
+ </ph>
+ <ph id="23">
+ One species of Palaeotragus developed more giraffe-like ossicones.
+ </ph>
+ <ph id="24">
+ They both were tall at the shoulder but still had short necks.
+ </ph>
+ <ph id="25">
+ For there the genus Giraffa evolved in the Pliocene period and Okapia evolved in the Pleistocene.
+ </ph>
+ <ph id="26">
+ The modern long-necked giraffe, Giraffa camelopardalis, appeared 1 million years ago.
+ </ph>
+ <ph id="27">
+ </ph>
+ </p>
+ <section id="2">
+ <title>
+ Classification
+ </title>
+ <p id="8">
+ <ph id="28">
+ There are nine generally accepted subspecies, differentiated by colour and pattern variations and range:
+ </ph>
+ </p>
+ <ul>
+ <li>
+ Reticulated or Somali Giraffe (G.c. reticulata) — large, polygonal liver-coloured spots outlined by a network of bright white lines. The blocks may sometimes appear deep red and may also cover the legs. Range: northeastern Kenya, Ethiopia, Somalia.
+ </li>
+ <li>
+ Angolan or Smoky Giraffe (G.c. angolensis) — large spots and some notches around the edges, extending down the entire lower leg. Range: Angola, Zambia.
+ </li>
+ <li>
+ Kordofan Giraffe (G.c. antiquorum) — smaller, more irregular spots that cover the inner legs. Range: western and southwestern Sudan.
+ </li>
+ <li>
+ Masai or Kilimanjaro Giraffe (G.c. tippelskirchi) — jagged-edged, vine-leaf shaped spots of dark chocolate on a yellowish background. Range: central and southern Kenya, Tanzania.
+ </li>
+ <li>
+ Nubian Giraffe (G.c. camelopardalis) — large, four-sided spots of chestnut brown on an off-white background and no spots on inner sides of the legs or below the hocks. Range: eastern Sudan, northeast Congo.
+ </li>
+ <li>
+ Rothschild Giraffe or Baringo Giraffe or Ugandan Giraffe (G.c. rothschildi) — deep brown, blotched or rectangular spots with poorly defined cream lines. Hocks may be spotted. Range: Uganda, north-central Kenya.
+ </li>
+ <li>
+ South African Giraffe (G.c. giraffa) — rounded or blotched spots, some with star-like extensions on a light tan background, running down to the hooves. Range: South Africa, Namibia, Botswana, Zimbabwe, Mozambique.
+ </li>
+ <li>
+ Thornicroft or Rhodesian Giraffe (G.c. thornicrofti) — star-shaped or leafy spots extend to the lower leg. Range: eastern Zambia.
+ </li>
+ <li>
+ West African or Nigerian Giraffe (G.c. peralta) — numerous pale, yellowish red spots. Range: Niger, Cameroon.
+ </li>
+ </ul>
+ <p id="9">
+ <ph id="29">
+ Some scientists regard Kordofan and West African Giraffes as a single subspecies; similarly with Nubian and Rothschild's Giraffes, and with Angolan and South African Giraffes.
+ </ph>
+ <ph id="30">
+ Further, some scientists regard all populations except the Masai Giraffes as a single subspecies.
+ </ph>
+ <ph id="31">
+ By contrast, scientists have proposed four other subspecies — Cape Giraffe (G.c.
+ </ph>
+ <ph id="32">
+ capensis), Lado Giraffe (G.c.
+ </ph>
+ <ph id="33">
+ cottoni), Congo Giraffe (G.c.
+ </ph>
+ <ph id="34">
+ congoensis), and Transvaal Giraffe (G.c.
+ </ph>
+ <ph id="35">
+ wardi) — but none of these is widely accepted.
+ </ph>
+ </p>
+ <p id="10">
+ <ph id="36">
+ Though giraffes of these populations interbreed freely under conditions of captivity, suggesting that they are subspecific populations, genetic testing published in 2007 has been interpreted to show that there may be at least six species of giraffe that are reproductively isolated and not interbreeding, even though no natural obstacles, like mountain ranges or impassable rivers block their mutual access.
+ </ph>
+ <ph id="37">
+ In fact, the study found that the two giraffe populations that live closest to each other— the reticulated giraffe (G.
+ </ph>
+ <ph id="38">
+ camelopardalis reticulata) of north Kenya, and the Masai giraffe (G.
+ </ph>
+ <ph id="39">
+ c.
+ </ph>
+ <ph id="40">
+ tippelskirchi) in south Kenya— separated genetically between 0.13 and 1.62 million years BP, judging from genetic drift in nuclear and mitochondrial DNA.
+ </ph>
+ </p>
+ <p id="11">
+ <ph id="41">
+ The implications for conservation of as many as eleven such cryptic species and sub-species were summarised by David Brown for BBC News: "Lumping all giraffes into one species obscures the reality that some kinds of giraffe are on the brink.
+ </ph>
+ <ph id="42">
+ Some of these populations number only a few hundred individuals and need immediate protection."
+ </ph>
+ </p>
+ <p id="12">
+ <ph id="43">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="4">
+ <title>
+ Anatomy and morphology
+ </title>
+ <refbody>
+ <p id="13">
+ <ph id="44">
+ Male giraffes are around 4.8-5.5&amp;#160;m (16-19&amp;#160;ft) tall at the horn tips, and normally weigh 1300-1700&amp;#160;kg (2900-3800&amp;#160;lb) Females are 30-60&amp;#160;cm (1-2&amp;#160;ft) shorter and weigh about 200-400&amp;#160;kg (400-800&amp;#160;lb) less than males.
+ </ph>
+ <ph id="45">
+ Giraffes have spots covering their entire bodies, except their underbellies, with each giraffe having a unique pattern of spots.
+ </ph>
+ </p>
+ <p id="14">
+ <ph id="46">
+ </ph>
+ </p>
+ <section id="3">
+ <title>
+ Horns
+ </title>
+ <p id="15">
+ <ph id="47">
+ Both sexes have horns, although the horns of a female are smaller.
+ </ph>
+ <ph id="48">
+ The prominent horns are formed from ossified cartilage and are called ossicones.
+ </ph>
+ <ph id="49">
+ The appearance of horns is a reliable method of identifying the sex of giraffes, with the females displaying tufts of hair on the top of the horns, where as males' horns tend to be bald on top — an effect of necking in combat.
+ </ph>
+ <ph id="50">
+ Males sometimes develop calcium deposits which form bumps on their skull as they age, which can give the appearance of up to three further horns.
+ </ph>
+ </p>
+ <p id="16">
+ <ph id="51">
+ </ph>
+ </p>
+ </section>
+ <section id="4">
+ <title>
+ Neck
+ </title>
+ <p id="17">
+ <ph id="52">
+ Giraffes have long necks, which they use to browse the leaves of trees.
+ </ph>
+ <ph id="53">
+ They possess seven vertebrae in the neck (the usual number for a mammal) that are elongated.
+ </ph>
+ <ph id="54">
+ The vertebrae are separated by highly flexible joints.
+ </ph>
+ <ph id="55">
+ The base of the neck has spines which project upward and form a hump over the shoulders.
+ </ph>
+ <ph id="56">
+ They have anchor muscles that hold the neck upright.
+ </ph>
+ </p>
+ <p id="18">
+ <ph id="57">
+ </ph>
+ </p>
+ </section>
+ <section id="5">
+ <title>
+ Legs and pacing
+ </title>
+ <p id="19">
+ <ph id="58">
+ Giraffes also have slightly elongated forelegs, about 10% longer than their hind legs.
+ </ph>
+ <ph id="59">
+ The pace of the giraffe is an amble, though when pursued it can run extremely fast.
+ </ph>
+ <ph id="60">
+ It can not sustain a lengthy chase.
+ </ph>
+ <ph id="61">
+ Its leg length compels an unusual gait with the left legs moving together followed by right (similar to pacing) at low speed, and the back legs crossing outside the front at high speed.
+ </ph>
+ <ph id="62">
+ When hunting adult giraffes, lions try to knock the lanky animal off its feet and pull it down.
+ </ph>
+ <ph id="63">
+ Giraffes are difficult and dangerous prey though, and when attacked the giraffe defends itself by kicking with great force.
+ </ph>
+ <ph id="64">
+ A single well-placed kick from an adult giraffe can shatter a lion's skull or break its spine.
+ </ph>
+ <ph id="65">
+ Lions are the only predators which pose a serious threat to an adult giraffe.
+ </ph>
+ </p>
+ <p id="20">
+ <ph id="66">
+ </ph>
+ </p>
+ </section>
+ <section id="6">
+ <title>
+ Circulatory system
+ </title>
+ <p id="21">
+ <ph id="67">
+ Modifications to the giraffe's structure have evolved, particularly to the circulatory system.
+ </ph>
+ <ph id="68">
+ A giraffe's heart, which can weigh up to 10&amp;#160;kg (22&amp;#160;lb) and measure about 60&amp;#160;cm (2&amp;#160;ft) long, has to generate around double the normal blood pressure for an average large mammal in order to maintain blood flow to the brain against gravity.
+ </ph>
+ <ph id="69">
+ In the upper neck, a complex pressure-regulation system called the rete mirabile prevents excess blood flow to the brain when the giraffe lowers its head to drink.
+ </ph>
+ <ph id="70">
+ Conversely, the blood vessels in the lower legs are under great pressure (because of the weight of fluid pressing down on them).
+ </ph>
+ <ph id="71">
+ In other animals such pressure would force the blood out through the capillary walls; giraffes, however, have a very tight sheath of thick skin over their lower limbs which maintains high extravascular pressure in exactly the same way as a pilot's g-suit.
+ </ph>
+ </p>
+ <p id="22">
+ <ph id="72">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="5">
+ <title>
+ Behaviour
+ </title>
+ <refbody>
+ <p id="23">
+ <ph id="73">
+ </ph>
+ </p>
+ <section id="7">
+ <title>
+ Social structure and breeding habits
+ </title>
+ <p id="24">
+ <ph id="74">
+ Female giraffes associate in groups of a dozen or so members, occasionally including a few younger males.
+ </ph>
+ <ph id="75">
+ Younger males tend to live in "bachelor"
+ </ph>
+ <ph id="76">
+ herds, with older males often leading solitary lives.
+ </ph>
+ <ph id="77">
+ Reproduction is polygamous, with a few older males impregnating all the fertile females in a herd.
+ </ph>
+ <ph id="78">
+ Male giraffes determine female fertility by tasting the female's urine in order to detect estrus, in a multi-step process known as the Flehmen response.
+ </ph>
+ </p>
+ <p id="25">
+ <ph id="79">
+ Giraffes will mingle with the other herbivores in the African bush.
+ </ph>
+ <ph id="80">
+ They are beneficial to be around because of their height.
+ </ph>
+ <ph id="81">
+ A giraffe is tall enough to have a much wider scope of an area and will watch out for predators.
+ </ph>
+ </p>
+ <p id="26">
+ <ph id="82">
+ </ph>
+ </p>
+ </section>
+ <section id="8">
+ <title>
+ Reproduction
+ </title>
+ <p id="27">
+ <ph id="83">
+ Giraffe gestation lasts between 14 and 15 months, after which a single calf is born.
+ </ph>
+ <ph id="84">
+ The mother gives birth standing up and the embryonic sack usually bursts when the baby falls to the ground.
+ </ph>
+ <ph id="85">
+ Newborn giraffes are about 1.8&amp;#160;m (6&amp;#160;ft) tall.
+ </ph>
+ </p>
+ <p id="28">
+ <ph id="86">
+ Within a few hours of being born, calves can run around and are indistinguishable from a week-old calf; however, for the first two weeks, they spend most of their time lying down, guarded by the mother.
+ </ph>
+ <ph id="87">
+ The young can fall prey to lions, leopards, spotted hyenas, and wild dogs.
+ </ph>
+ <ph id="88">
+ It has been speculated that their characteristic spotted pattern provides a certain degree of camouflage.
+ </ph>
+ <ph id="89">
+ Only 25 to 50% of giraffe calves reach adulthood; the life expectancy is between 20 and 25 years in the wild and 28 years in captivity (Encyclopedia of Animals).
+ </ph>
+ </p>
+ <p id="29">
+ <ph id="90">
+ </ph>
+ </p>
+ </section>
+ <section id="9">
+ <title>
+ Necking
+ </title>
+ <p id="30">
+ <ph id="91">
+ As noted above, males often engage in necking, which has been described as having various functions.
+ </ph>
+ <ph id="92">
+ One of these is combat.
+ </ph>
+ <ph id="93">
+ Battles can be fatal, but are more often less severe.
+ </ph>
+ <ph id="94">
+ The longer the neck, and the heavier the head at the end of the neck, the greater the force a giraffe is able to deliver in a blow.
+ </ph>
+ <ph id="95">
+ It has also been observed that males that are successful in necking have greater access to estrous females, so the length of the neck may be a product of sexual selection.
+ </ph>
+ </p>
+ <p id="31">
+ <ph id="96">
+ After a necking duel, a giraffe can land a powerful blow with his head — occasionally knocking a male opponent to the ground.
+ </ph>
+ <ph id="97">
+ These fights rarely last more than a few minutes or end in physical harm.
+ </ph>
+ </p>
+ <p id="32">
+ <ph id="98">
+ Another function of necking is affectionate and sexual, in which two males will caress and court each other, leading up to mounting and climax.
+ </ph>
+ <ph id="99">
+ Same sex relations are more frequent than heterosexual behaviour.
+ </ph>
+ <ph id="100">
+ In one area 94% of mounting incidents were of a homosexual nature.
+ </ph>
+ <ph id="101">
+ The proportion of same sex courtships varies between 30 and 75%, and at any given time one in twenty males will be engaged in affectionate necking behaviour with another male.
+ </ph>
+ <ph id="102">
+ Females, on the other hand, only appear to have same sex relations in 1% of mounting incidents.
+ </ph>
+ </p>
+ <p id="33">
+ <ph id="103">
+ </ph>
+ </p>
+ </section>
+ <section id="10">
+ <title>
+ Stereotypic behavior
+ </title>
+ <p id="34">
+ <ph id="104">
+ Many animals when kept in captivity, such as in zoos, display abnormal behaviours.
+ </ph>
+ <ph id="105">
+ Such unnatural behaviours are known as stereotypic behaviours.
+ </ph>
+ <ph id="106">
+ In particular, giraffes show distinct patterns of stereotypic behaviours when removed from their natural environment.
+ </ph>
+ <ph id="107">
+ Due to a subconscious response to suckle milk from their mother, something which many human-reared giraffes and other captive animals do not experience, giraffes resort instead to excessive tongue use on inanimate objects.
+ </ph>
+ </p>
+ <p id="35">
+ <ph id="108">
+ Due to the obvious social and cultural discomfort associated with the addition of milk delivery devices, animal enclosures are often enriched with other stimuli, such as food and mental distractions (toys, scent markings etc.).
+ </ph>
+ <ph id="109">
+ This operates as a distraction, removing the giraffe’s focus from its instinctual tendencies towards suckling, resulting in tongue lolling and licking of objects in close proximity.
+ </ph>
+ </p>
+ <p id="36">
+ <ph id="110">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="6">
+ <title>
+ Feeding and cleaning
+ </title>
+ <refbody>
+ <p id="37">
+ <ph id="111">
+ The giraffe browses on the twigs of trees, preferring trees of the genus Mimosa; but it appears that it can live without inconvenience on other vegetable food.
+ </ph>
+ <ph id="112">
+ A giraffe can eat 63&amp;#160;kg (140&amp;#160;lb) of leaves and twigs daily.
+ </ph>
+ <ph id="113">
+ As ruminants, they first chew their food, swallow for processing and then visibly regurgitate the semi-digested cud up their necks and back into the mouth, in order to chew again.
+ </ph>
+ <ph id="114">
+ This process is usually repeated several times for each mouthful.
+ </ph>
+ <ph id="115">
+ In captivity they can sense food when humans are around and will ask for some by sticking their head up close to them and extending their tongue out.
+ </ph>
+ </p>
+ <p id="38">
+ <ph id="116">
+ A giraffe will clean off any bugs that appear on its face with its extremely long tongue (about 45&amp;#160;cm/18&amp;#160;in).
+ </ph>
+ <ph id="117">
+ The tongue is tough on account of the giraffe's diet, which can include thorns from the trees that they eat.
+ </ph>
+ <ph id="118">
+ In Southern Africa, giraffes feed on all acacias, especially Acacia erioloba, and possess a specially-adapted tongue and lips that are tough enough to withstand, or even ignore, the vicious thorns of this plant.
+ </ph>
+ </p>
+ <p id="39">
+ <ph id="119">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="7">
+ <title>
+ Sleep
+ </title>
+ <refbody>
+ <p id="40">
+ <ph id="120">
+ The giraffe has one of the shortest sleep requirements of any mammal, which is between 10 minutes and two hours in a 24-hour period, averaging 1.9 hours per day.
+ </ph>
+ </p>
+ <p id="41">
+ <ph id="121">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="8">
+ <title>
+ Sounds
+ </title>
+ <refbody>
+ <p id="42">
+ <ph id="122">
+ Although generally quiet and not vocal, giraffes have been heard to make various sounds.
+ </ph>
+ <ph id="123">
+ Courting males will emit loud coughs.
+ </ph>
+ <ph id="124">
+ Females will call their young by whistling or bellowing.
+ </ph>
+ <ph id="125">
+ Calves will bleat, moo, or make mewing sounds.
+ </ph>
+ <ph id="126">
+ In addition, giraffes will grunt, snort, hiss, or make strange flute-like sounds.
+ </ph>
+ <ph id="127">
+ Recent research has shown evidence that the animal communicates at an infrasound level.
+ </ph>
+ </p>
+ <p id="43">
+ <ph id="128">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="9">
+ <title>
+ Human interactions
+ </title>
+ <refbody>
+ <p id="44">
+ <ph id="129">
+ </ph>
+ </p>
+ <section id="11">
+ <title>
+ Conservation
+ </title>
+ <p id="45">
+ <ph id="130">
+ Giraffes are hunted for their hides, hair, and meat.
+ </ph>
+ <ph id="131">
+ In addition, habitat destruction also hurts the giraffe.
+ </ph>
+ <ph id="132">
+ In the Sahel trees are cut down for firewood and to make way for livestock.
+ </ph>
+ <ph id="133">
+ Normally, giraffes are able to cope with livestock since they feed in the trees above their heads.
+ </ph>
+ <ph id="134">
+ The giraffe population is shrinking in West Africa.
+ </ph>
+ <ph id="135">
+ However, the populations in eastern and southern Africa are stable and, due to the popularity of privately-owned game ranches and sanctuaries (i.e.
+ </ph>
+ <ph id="136">
+ Bour-Algi Giraffe Sanctuary), are expanding.
+ </ph>
+ <ph id="137">
+ The giraffe is a protected species in most of its range.
+ </ph>
+ <ph id="138">
+ The total African giraffe population has been estimated to range from 110,000 to 150,000.
+ </ph>
+ <ph id="139">
+ Kenya (45,000), Tanzania (30,000), and Botswana (12,000), have the largest national populations.
+ </ph>
+ </p>
+ <p id="46">
+ <ph id="140">
+ An unexpected danger to giraffes in captivity is that, as they are typically the tallest objects in a zoo, giraffes are at increased risk of being struck by lightning.
+ </ph>
+ <ph id="141">
+ In the wild, this hazard is reduced by the presence of trees; as well, the giraffe's natural habitat range has an extremely low occurrence of lightning -- NASA's satellite lightning detection system indicates that the area receives an average of less than one cloud-to-ground flash per square kilometre per year.
+ </ph>
+ </p>
+ <p id="47">
+ <ph id="142">
+ </ph>
+ </p>
+ </section>
+ <section id="12">
+ <title>
+ In art and culture
+ </title>
+ <p id="48">
+ <ph id="143">
+ Giraffes can be seen in paintings, including the famous painting of a giraffe which was taken from Africa to China by Admiral Zheng He in 1414.
+ </ph>
+ <ph id="144">
+ The giraffe was placed in a Ming Dynasty zoo.
+ </ph>
+ </p>
+ <p id="49">
+ <ph id="145">
+ The Medici giraffe was a giraffe presented to Lorenzo de' Medici in 1486.
+ </ph>
+ <ph id="146">
+ It caused a great stir on its arrival in Florence, being reputedly the first living giraffe to be seen in Italy since the days of Ancient Rome.
+ </ph>
+ <ph id="147">
+ Another famous giraffe, called Zarafa, was brought from Africa to Paris in the early 1800s and kept in a menagerie for 18 years.
+ </ph>
+ </p>
+ <p id="50">
+ <ph id="148">
+ Giraffe is a novel by the author J.
+ </ph>
+ <ph id="149">
+ M.
+ </ph>
+ <ph id="150">
+ Ledgard.
+ </ph>
+ <ph id="151">
+ The work concerns a true incident in which 49 giraffes were slaughtered in the Czech Republic (then Czechoslovakia) in 1975 following the suspected outbreak of disease amongst the group.
+ </ph>
+ <ph id="152">
+ The novel contains extensive information about the species, including the long history of European fascination with the beast and its captivity in zoos.
+ </ph>
+ </p>
+ <p id="51">
+ <ph id="153">
+ Notable fictional giraffes include:
+ </ph>
+ </p>
+ <ul>
+ <li>
+ Toys "R" Us mascot Geoffrey the Giraffe. He was originally portrayed as a cartoon giraffe but in the 2001 commercials he was portrayed as a real-life giraffe who talks; an animatronic version of Geoffrey the Giraffe (created by Stan Winston Studios), was voiced by Jim Hanks in commercials for radio and television.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ Longrack of the Transformers universe
+ </li>
+ <li>
+ Girafarig from the Pokémon franchise
+ </li>
+ <li>
+ Melman from Madagascar
+ </li>
+ </ul>
+ <p id="52">
+ <ph id="154">
+ Giraffes have also appeared as background characters in various other animated works such as Dumbo and The Lion King.
+ </ph>
+ </p>
+ <p id="53">
+ <ph id="155">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="10">
+ <title>
+ References
+ </title>
+ <refbody>
+ <section id="13">
+ <ol>
+ <li id="cite_note-0">
+ ^ Antelope Specialist Group (1996). Giraffa camelopardalis. 2006 IUCN Red List of Threatened Species. IUCN 2006. Retrieved on 5 May 2006.
+ </li>
+ <li id="cite_note-1">
+ ^ San Diego Zoo giraffe fact sheet Retrieved 14 August 2006.
+ </li>
+ <li id="cite_note-2">
+ ^ Camelopard
+ </li>
+ <li id="cite_note-3">
+ ^ Stevens, J. (1993). Familiar Strangers. International Wildlife, 23, 6-10.
+ </li>
+ <li id="cite_note-4">
+ ^ David Brown, Rick A Brenneman, et al., "Extensive Population Genetic Structure in the Giraffe", BioMedCentral Biology. Reported in BBC News, "Not one but 'six giraffe species'", 21 December 2007 and in ScienceDaily, "Giraffes And Frogs Provide More Evidence Of New Species Hidden In Plain Sight", 21 December 2007
+ </li>
+ <li id="cite_note-5">
+ ^ San Diego Zoo's Animal Bytes: Giraffe
+ </li>
+ <li id="cite_note-6">
+ ^ Robert E. Simmons and Lue Scheepers: Winning by a neck: Sexual selection in the evolution of giraffe. The American Naturalist, 148 (1996): pp. 771-786.
+ </li>
+ <li id="cite_note-7">
+ ^ Bruce Bagemihl, Biological Exuberance: Animal Homosexuality and Natural Diversity, St. Martin's Press, 1999; pp.391-393
+ </li>
+ <li id="cite_note-8">
+ ^ Jentz, D.C. &amp;amp; A.B. Gull 1978. Towards a definition of abnormal activity: stereotypic behaviours in captive primates. Mamm. Ecol. 12: 145–154.
+ </li>
+ <li id="cite_note-9">
+ ^ Harrison, J.C, Q.F. George &amp;amp; C.C. Cronk 2001. Stereotypic behaviour in zoo animals. J. Zoo Sc. 23: 71–86.
+ </li>
+ <li id="cite_note-10">
+ ^ BBC - Science &amp;amp; Nature - Human Body and Mind - What is sleep
+ </li>
+ <li id="cite_note-11">
+ ^ Infrasound From the Giraffe
+ </li>
+ <li id="cite_note-12">
+ ^ East, R. 1998, in: African Antelope Database 1998. IUCN/SSC Antelope Specialist Group Report.
+ </li>
+ <li id="cite_note-13">
+ ^ Lightning strikes giraffes
+ </li>
+ </ol>
+ </section>
+ <p id="54">
+ <ph id="156">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="11">
+ <title>
+ External links
+ </title>
+ <refbody>
+ <section id="14">
+ <ul>
+ <li>
+ Video - Giraffe birth at the San Francisco Zoo
+ </li>
+ <li>
+ Giraffes: Wildlife summary from the African Wildlife Foundation
+ </li>
+ <li>
+ ARKive - images and movies of the giraffe (Giraffa camelopardalis).
+ </li>
+ <li>
+ Introduction to the history of the Giraffe in Middle Ages (French)
+ </li>
+ <li>
+ Animal Diversity Web - Giraffa camelopardalis
+ </li>
+ <li>
+ Giraffe Central web directory
+ </li>
+ <li>
+ IUCN Red List of Threatened Species
+ </li>
+ <li>
+ PBS Nature: Tall Blondes (Giraffes)
+ </li>
+ <li>
+ Matt's World of Wicked Giraffes
+ </li>
+ <li>
+ Mating System
+ </li>
+ <li>
+ Giraffe Info Sheet
+ </li>
+ <li>
+ Long-term suppression of fertility in female giraffe using the GnRH agonist deslorelin as a long-acting implant
+ </li>
+ <li>
+ Erik Ringmar. "Audience for a Giraffe: European Expansionism and the Quest for the Exotic". Journal of World History, 17:4, December, 2006. pp. 353-97.
+ </li>
+ </ul>
+ </section>
+ <p id="55">
+ <ph id="157">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="imagelist">
+ <refbody>
+ <image href="#DEMOLIBRARY#/images/230px-Giraffe_standing.jpg">
+ <alt>
+ 230px-Giraffe_standing.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Status_iucn2.3_CD.svg.png">
+ <alt>
+ 180px-Status_iucn2.3_CD.svg.png
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/230px-Giraffa_camelopardalis_subspecies_map.jpg">
+ <alt>
+ Range map
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Climacoceras_gentryi_e.jpg">
+ <alt>
+ Comparison of the African Miocene giraffids: Palaeotragus (two top)and Climacoceras (two bottom)
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-GiraffeSkelLyd2.png">
+ <alt>
+ Giraffe skeleton as illustrated by Richard Lydekker.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Giraffe08_-_melbourne_zoo_edit.jpg">
+ <alt>
+ Giraffe in captivity at the Melbourne Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/300px-Namibie_Etosha_Girafe_01.jpg">
+ <alt>
+ Giraffes bending down to drink
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Giraffes_IMG_9614.JPG">
+ <alt>
+ A male(bull) with a baby(calf) giraffe at the San Francisco Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Giraffa_camelopardalis_angolensis_%28mating%29.jpg">
+ <alt>
+ Mating Angolan Giraffes at Chudop waterhole, Etosha, Namibia.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Giraffe_Ithala_KZN_South_Africa_Luca_Galuzzi_2004.JPG">
+ <alt>
+ Two males necking.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Giraffe_%28head%29.jpg">
+ <alt>
+ Giraffes use their long, prehensile tongues to extend their reach.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Wildlifephotography.jpg">
+ <alt>
+ Lone giraffe at Lake Nakuru National Park, Kenya
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-ShenDuGiraffePainting.jpg">
+ <alt>
+ Painting of a giraffe taken to China by Admiral Zheng He
+ </alt>
+ </image>
+ </refbody>
+ </reference>
+</reference> \ No newline at end of file
diff --git a/Processing/demolibrary/images/120px-Siberian-Tiger.jpg b/Processing/demolibrary/images/120px-Siberian-Tiger.jpg
new file mode 100644
index 0000000..38c7459
--- /dev/null
+++ b/Processing/demolibrary/images/120px-Siberian-Tiger.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/120px-Siberischer_tiger_de_edit02.jpg b/Processing/demolibrary/images/120px-Siberischer_tiger_de_edit02.jpg
new file mode 100644
index 0000000..ba8b9ad
--- /dev/null
+++ b/Processing/demolibrary/images/120px-Siberischer_tiger_de_edit02.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/120px-Tiger_cooling_off_at_Bandhavghar.jpg b/Processing/demolibrary/images/120px-Tiger_cooling_off_at_Bandhavghar.jpg
new file mode 100644
index 0000000..e5db9b5
--- /dev/null
+++ b/Processing/demolibrary/images/120px-Tiger_cooling_off_at_Bandhavghar.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/120px-Vibrissae_of_a_Tiger_at_Chester_Zoo.jpg b/Processing/demolibrary/images/120px-Vibrissae_of_a_Tiger_at_Chester_Zoo.jpg
new file mode 100644
index 0000000..59bc825
--- /dev/null
+++ b/Processing/demolibrary/images/120px-Vibrissae_of_a_Tiger_at_Chester_Zoo.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/140px-GD-EG-KomOmbo016.JPG b/Processing/demolibrary/images/140px-GD-EG-KomOmbo016.JPG
new file mode 100644
index 0000000..3ce203e
--- /dev/null
+++ b/Processing/demolibrary/images/140px-GD-EG-KomOmbo016.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/140px-Jerusalem-coat-of-arms.svg.png b/Processing/demolibrary/images/140px-Jerusalem-coat-of-arms.svg.png
new file mode 100644
index 0000000..7acb7ad
--- /dev/null
+++ b/Processing/demolibrary/images/140px-Jerusalem-coat-of-arms.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/140px-Lion_pair2.jpg b/Processing/demolibrary/images/140px-Lion_pair2.jpg
new file mode 100644
index 0000000..1f20c96
--- /dev/null
+++ b/Processing/demolibrary/images/140px-Lion_pair2.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/140px-P_l_Bleyenberghi.jpg b/Processing/demolibrary/images/140px-P_l_Bleyenberghi.jpg
new file mode 100644
index 0000000..b2eda88
--- /dev/null
+++ b/Processing/demolibrary/images/140px-P_l_Bleyenberghi.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Climacoceras_gentryi_e.jpg b/Processing/demolibrary/images/150px-Climacoceras_gentryi_e.jpg
new file mode 100644
index 0000000..ad542d2
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Climacoceras_gentryi_e.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Giraffa_camelopardalis_angolensis_%28mating%29.jpg b/Processing/demolibrary/images/150px-Giraffa_camelopardalis_angolensis_%28mating%29.jpg
new file mode 100644
index 0000000..6786bee
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Giraffa_camelopardalis_angolensis_%28mating%29.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Giraffes_IMG_9614.JPG b/Processing/demolibrary/images/150px-Giraffes_IMG_9614.JPG
new file mode 100644
index 0000000..decd5b6
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Giraffes_IMG_9614.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Kuniyoshi_Utagawa%2C_Tiger.jpg b/Processing/demolibrary/images/150px-Kuniyoshi_Utagawa%2C_Tiger.jpg
new file mode 100644
index 0000000..9631529
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Kuniyoshi_Utagawa%2C_Tiger.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Mare_and_foal_%28Kvetina-Marie%29.jpg b/Processing/demolibrary/images/150px-Mare_and_foal_%28Kvetina-Marie%29.jpg
new file mode 100644
index 0000000..4b5fc4a
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Mare_and_foal_%28Kvetina-Marie%29.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Tigergebiss.jpg b/Processing/demolibrary/images/150px-Tigergebiss.jpg
new file mode 100644
index 0000000..d9444be
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Tigergebiss.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Zebra_eating.JPG b/Processing/demolibrary/images/150px-Zebra_eating.JPG
new file mode 100644
index 0000000..3464f6f
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Zebra_eating.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/150px-Zoo_UL%2C_Hartmann%27s_mountain_zebra.jpg b/Processing/demolibrary/images/150px-Zoo_UL%2C_Hartmann%27s_mountain_zebra.jpg
new file mode 100644
index 0000000..7f835f2
--- /dev/null
+++ b/Processing/demolibrary/images/150px-Zoo_UL%2C_Hartmann%27s_mountain_zebra.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-1990tiger.PNG b/Processing/demolibrary/images/180px-1990tiger.PNG
new file mode 100644
index 0000000..cd1f25d
--- /dev/null
+++ b/Processing/demolibrary/images/180px-1990tiger.PNG
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Asiatic.lioness.arp.jpg b/Processing/demolibrary/images/180px-Asiatic.lioness.arp.jpg
new file mode 100644
index 0000000..3554c45
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Asiatic.lioness.arp.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Bertramliger.jpg b/Processing/demolibrary/images/180px-Bertramliger.jpg
new file mode 100644
index 0000000..d725f15
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Bertramliger.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Circus_Lion_Tamer.jpg b/Processing/demolibrary/images/180px-Circus_Lion_Tamer.jpg
new file mode 100644
index 0000000..f6e0ac8
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Circus_Lion_Tamer.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Durer_lions_%28sketch%29.jpg b/Processing/demolibrary/images/180px-Durer_lions_%28sketch%29.jpg
new file mode 100644
index 0000000..7b5ccc7
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Durer_lions_%28sketch%29.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Female_Lion.JPG b/Processing/demolibrary/images/180px-Female_Lion.JPG
new file mode 100644
index 0000000..554b29c
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Female_Lion.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Giraffe08_-_melbourne_zoo_edit.jpg b/Processing/demolibrary/images/180px-Giraffe08_-_melbourne_zoo_edit.jpg
new file mode 100644
index 0000000..be7f5df
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Giraffe08_-_melbourne_zoo_edit.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-GiraffeSkelLyd2.png b/Processing/demolibrary/images/180px-GiraffeSkelLyd2.png
new file mode 100644
index 0000000..ecd3ba1
--- /dev/null
+++ b/Processing/demolibrary/images/180px-GiraffeSkelLyd2.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Giraffe_%28head%29.jpg b/Processing/demolibrary/images/180px-Giraffe_%28head%29.jpg
new file mode 100644
index 0000000..5a8503f
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Giraffe_%28head%29.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Giraffe_Ithala_KZN_South_Africa_Luca_Galuzzi_2004.JPG b/Processing/demolibrary/images/180px-Giraffe_Ithala_KZN_South_Africa_Luca_Galuzzi_2004.JPG
new file mode 100644
index 0000000..1b4c128
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Giraffe_Ithala_KZN_South_Africa_Luca_Galuzzi_2004.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/180px-HansomeLion_002.jpg b/Processing/demolibrary/images/180px-HansomeLion_002.jpg
new file mode 100644
index 0000000..368cbc2
--- /dev/null
+++ b/Processing/demolibrary/images/180px-HansomeLion_002.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Lightmatter_lioness.jpg b/Processing/demolibrary/images/180px-Lightmatter_lioness.jpg
new file mode 100644
index 0000000..e98ee60
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Lightmatter_lioness.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Lion_-_melbourne_zoo.jpg b/Processing/demolibrary/images/180px-Lion_-_melbourne_zoo.jpg
new file mode 100644
index 0000000..0a50336
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Lion_-_melbourne_zoo.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Lion_at_zoo.jpg b/Processing/demolibrary/images/180px-Lion_at_zoo.jpg
new file mode 100644
index 0000000..179a438
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Lion_at_zoo.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Lion_cub_with_mother.jpg b/Processing/demolibrary/images/180px-Lion_cub_with_mother.jpg
new file mode 100644
index 0000000..b0474bd
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Lion_cub_with_mother.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Lion_cubs_Serengeti.jpg b/Processing/demolibrary/images/180px-Lion_cubs_Serengeti.jpg
new file mode 100644
index 0000000..6f24863
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Lion_cubs_Serengeti.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Male_Lion_and_Cub_Chitwa_South_Africa_Luca_Galuzzi_2004.JPG b/Processing/demolibrary/images/180px-Male_Lion_and_Cub_Chitwa_South_Africa_Luca_Galuzzi_2004.JPG
new file mode 100644
index 0000000..9c653dc
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Male_Lion_and_Cub_Chitwa_South_Africa_Luca_Galuzzi_2004.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Maneating_lion.jpg b/Processing/demolibrary/images/180px-Maneating_lion.jpg
new file mode 100644
index 0000000..272fa19
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Maneating_lion.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Maneless_lion_from_Tsavo_East_National_Park.png b/Processing/demolibrary/images/180px-Maneless_lion_from_Tsavo_East_National_Park.png
new file mode 100644
index 0000000..e9f8017
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Maneless_lion_from_Tsavo_East_National_Park.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Map_Guj_Nat_Parks_Sanctuary.png b/Processing/demolibrary/images/180px-Map_Guj_Nat_Parks_Sanctuary.png
new file mode 100644
index 0000000..eb58c04
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Map_Guj_Nat_Parks_Sanctuary.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Matha.png b/Processing/demolibrary/images/180px-Matha.png
new file mode 100644
index 0000000..2bab22d
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Matha.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Panthera_leo_Kruger_Skull.jpg b/Processing/demolibrary/images/180px-Panthera_leo_Kruger_Skull.jpg
new file mode 100644
index 0000000..d82237b
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Panthera_leo_Kruger_Skull.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Panthera_tigris_amoyensis.jpg b/Processing/demolibrary/images/180px-Panthera_tigris_amoyensis.jpg
new file mode 100644
index 0000000..b549171
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Panthera_tigris_amoyensis.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Panthera_tigris_balica.jpg b/Processing/demolibrary/images/180px-Panthera_tigris_balica.jpg
new file mode 100644
index 0000000..d58bcdb
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Panthera_tigris_balica.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Panthera_tigris_sondaica_01.jpg b/Processing/demolibrary/images/180px-Panthera_tigris_sondaica_01.jpg
new file mode 100644
index 0000000..229a2e3
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Panthera_tigris_sondaica_01.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Panthera_tigris_sumatran_subspecies.jpg b/Processing/demolibrary/images/180px-Panthera_tigris_sumatran_subspecies.jpg
new file mode 100644
index 0000000..8b4cfcf
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Panthera_tigris_sumatran_subspecies.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Panthera_tigris_virgata.jpg b/Processing/demolibrary/images/180px-Panthera_tigris_virgata.jpg
new file mode 100644
index 0000000..79c42ed
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Panthera_tigris_virgata.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-PregnantLioness.jpg b/Processing/demolibrary/images/180px-PregnantLioness.jpg
new file mode 100644
index 0000000..f0b5ac1
--- /dev/null
+++ b/Processing/demolibrary/images/180px-PregnantLioness.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Royal_Arms_of_Scotland.svg.png b/Processing/demolibrary/images/180px-Royal_Arms_of_Scotland.svg.png
new file mode 100644
index 0000000..5f48733
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Royal_Arms_of_Scotland.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-ShenDuGiraffePainting.jpg b/Processing/demolibrary/images/180px-ShenDuGiraffePainting.jpg
new file mode 100644
index 0000000..eefd92c
--- /dev/null
+++ b/Processing/demolibrary/images/180px-ShenDuGiraffePainting.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Status_iucn2.3_CD.svg.png b/Processing/demolibrary/images/180px-Status_iucn2.3_CD.svg.png
new file mode 100644
index 0000000..78f21bf
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Status_iucn2.3_CD.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Status_iucn2.3_EN.svg.png b/Processing/demolibrary/images/180px-Status_iucn2.3_EN.svg.png
new file mode 100644
index 0000000..1c3b4da
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Status_iucn2.3_EN.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Status_iucn3.1_VU.svg.png b/Processing/demolibrary/images/180px-Status_iucn3.1_VU.svg.png
new file mode 100644
index 0000000..eee9fbf
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Status_iucn3.1_VU.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Tiger_032.jpg b/Processing/demolibrary/images/180px-Tiger_032.jpg
new file mode 100644
index 0000000..d1418a4
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Tiger_032.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Tiger_Bandavgarh_adjusted_levels.jpg b/Processing/demolibrary/images/180px-Tiger_Bandavgarh_adjusted_levels.jpg
new file mode 100644
index 0000000..6cdde7d
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Tiger_Bandavgarh_adjusted_levels.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Tiger_in_the_snow_at_the_Detroit_Zoo_March_2008_pic_2.jpg b/Processing/demolibrary/images/180px-Tiger_in_the_snow_at_the_Detroit_Zoo_March_2008_pic_2.jpg
new file mode 100644
index 0000000..3ef7b7f
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Tiger_in_the_snow_at_the_Detroit_Zoo_March_2008_pic_2.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Tiger_in_the_water.jpg b/Processing/demolibrary/images/180px-Tiger_in_the_water.jpg
new file mode 100644
index 0000000..fad050a
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Tiger_in_the_water.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Tigress-Jowlagiri.jpg b/Processing/demolibrary/images/180px-Tigress-Jowlagiri.jpg
new file mode 100644
index 0000000..333901f
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Tigress-Jowlagiri.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-White_Lion.jpg b/Processing/demolibrary/images/180px-White_Lion.jpg
new file mode 100644
index 0000000..e5643ec
--- /dev/null
+++ b/Processing/demolibrary/images/180px-White_Lion.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/180px-Zebra_Dallas_Zoo_1974.jpg b/Processing/demolibrary/images/180px-Zebra_Dallas_Zoo_1974.jpg
new file mode 100644
index 0000000..998db2b
--- /dev/null
+++ b/Processing/demolibrary/images/180px-Zebra_Dallas_Zoo_1974.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/200px-Lions_and_a_Zebra_a.jpg b/Processing/demolibrary/images/200px-Lions_and_a_Zebra_a.jpg
new file mode 100644
index 0000000..28a2cda
--- /dev/null
+++ b/Processing/demolibrary/images/200px-Lions_and_a_Zebra_a.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/200px-Zebra-tame-jumping.jpg b/Processing/demolibrary/images/200px-Zebra-tame-jumping.jpg
new file mode 100644
index 0000000..763d6f5
--- /dev/null
+++ b/Processing/demolibrary/images/200px-Zebra-tame-jumping.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/200px-Zebra2.jpg b/Processing/demolibrary/images/200px-Zebra2.jpg
new file mode 100644
index 0000000..9391c1d
--- /dev/null
+++ b/Processing/demolibrary/images/200px-Zebra2.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/200px-Zebra_Botswana_edit02.jpg b/Processing/demolibrary/images/200px-Zebra_Botswana_edit02.jpg
new file mode 100644
index 0000000..9659609
--- /dev/null
+++ b/Processing/demolibrary/images/200px-Zebra_Botswana_edit02.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/200px-Zebra_rownikowa_Equus_burchelli_boehmi_RB3.jpg b/Processing/demolibrary/images/200px-Zebra_rownikowa_Equus_burchelli_boehmi_RB3.jpg
new file mode 100644
index 0000000..9b4635f
--- /dev/null
+++ b/Processing/demolibrary/images/200px-Zebra_rownikowa_Equus_burchelli_boehmi_RB3.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/220px-Tiger_distribution3.PNG b/Processing/demolibrary/images/220px-Tiger_distribution3.PNG
new file mode 100644
index 0000000..c127055
--- /dev/null
+++ b/Processing/demolibrary/images/220px-Tiger_distribution3.PNG
Binary files differ
diff --git a/Processing/demolibrary/images/225px-Una-lion.jpg b/Processing/demolibrary/images/225px-Una-lion.jpg
new file mode 100644
index 0000000..43538a0
--- /dev/null
+++ b/Processing/demolibrary/images/225px-Una-lion.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/230px-037tiger.jpg b/Processing/demolibrary/images/230px-037tiger.jpg
new file mode 100644
index 0000000..6ca077e
--- /dev/null
+++ b/Processing/demolibrary/images/230px-037tiger.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/230px-Giraffa_camelopardalis_subspecies_map.jpg b/Processing/demolibrary/images/230px-Giraffa_camelopardalis_subspecies_map.jpg
new file mode 100644
index 0000000..a603eb1
--- /dev/null
+++ b/Processing/demolibrary/images/230px-Giraffa_camelopardalis_subspecies_map.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/230px-Giraffe_standing.jpg b/Processing/demolibrary/images/230px-Giraffe_standing.jpg
new file mode 100644
index 0000000..53ca8e4
--- /dev/null
+++ b/Processing/demolibrary/images/230px-Giraffe_standing.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/230px-Golden_tiger_1_-_Buffalo_Zoo.jpg b/Processing/demolibrary/images/230px-Golden_tiger_1_-_Buffalo_Zoo.jpg
new file mode 100644
index 0000000..6f4e63a
--- /dev/null
+++ b/Processing/demolibrary/images/230px-Golden_tiger_1_-_Buffalo_Zoo.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/230px-Singapore_Zoo_Tigers.jpg b/Processing/demolibrary/images/230px-Singapore_Zoo_Tigers.jpg
new file mode 100644
index 0000000..55ec159
--- /dev/null
+++ b/Processing/demolibrary/images/230px-Singapore_Zoo_Tigers.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/230px-TigerSkelLyd1.png b/Processing/demolibrary/images/230px-TigerSkelLyd1.png
new file mode 100644
index 0000000..b80671f
--- /dev/null
+++ b/Processing/demolibrary/images/230px-TigerSkelLyd1.png
Binary files differ
diff --git a/Processing/demolibrary/images/240px-7_lions.jpg b/Processing/demolibrary/images/240px-7_lions.jpg
new file mode 100644
index 0000000..380ce53
--- /dev/null
+++ b/Processing/demolibrary/images/240px-7_lions.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/240px-ElephantbackTigerHunt.jpg b/Processing/demolibrary/images/240px-ElephantbackTigerHunt.jpg
new file mode 100644
index 0000000..21dea46
--- /dev/null
+++ b/Processing/demolibrary/images/240px-ElephantbackTigerHunt.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/240px-Flag_of_Sri_Lanka.svg.png b/Processing/demolibrary/images/240px-Flag_of_Sri_Lanka.svg.png
new file mode 100644
index 0000000..15a3428
--- /dev/null
+++ b/Processing/demolibrary/images/240px-Flag_of_Sri_Lanka.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/240px-Stud_327_with_Blesbuck.jpg b/Processing/demolibrary/images/240px-Stud_327_with_Blesbuck.jpg
new file mode 100644
index 0000000..b1cc57c
--- /dev/null
+++ b/Processing/demolibrary/images/240px-Stud_327_with_Blesbuck.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/240px-TigerSkinning.jpg b/Processing/demolibrary/images/240px-TigerSkinning.jpg
new file mode 100644
index 0000000..38b8bad
--- /dev/null
+++ b/Processing/demolibrary/images/240px-TigerSkinning.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Beautiful_Zebra_in_South_Africa.JPG b/Processing/demolibrary/images/250px-Beautiful_Zebra_in_South_Africa.JPG
new file mode 100644
index 0000000..2bf7caa
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Beautiful_Zebra_in_South_Africa.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Equus_grevyi_in_Kenya_%28male%29.jpg b/Processing/demolibrary/images/250px-Equus_grevyi_in_Kenya_%28male%29.jpg
new file mode 100644
index 0000000..5326a3a
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Equus_grevyi_in_Kenya_%28male%29.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-LAzooZebra.jpg b/Processing/demolibrary/images/250px-LAzooZebra.jpg
new file mode 100644
index 0000000..74f6444
--- /dev/null
+++ b/Processing/demolibrary/images/250px-LAzooZebra.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Lion_distribution.svg.png b/Processing/demolibrary/images/250px-Lion_distribution.svg.png
new file mode 100644
index 0000000..ac049dd
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Lion_distribution.svg.png
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Lion_in_Ngorongoro_Crater%2C_Tanzania.jpg b/Processing/demolibrary/images/250px-Lion_in_Ngorongoro_Crater%2C_Tanzania.jpg
new file mode 100644
index 0000000..bd41836
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Lion_in_Ngorongoro_Crater%2C_Tanzania.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Lion_in_masai_mara.jpg b/Processing/demolibrary/images/250px-Lion_in_masai_mara.jpg
new file mode 100644
index 0000000..0bf38af
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Lion_in_masai_mara.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Lionesses%2C_Masai_Mara%2C_Kenya.jpg b/Processing/demolibrary/images/250px-Lionesses%2C_Masai_Mara%2C_Kenya.jpg
new file mode 100644
index 0000000..a850cde
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Lionesses%2C_Masai_Mara%2C_Kenya.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Map_Guj_Nat_Parks_Sanctuary.png b/Processing/demolibrary/images/250px-Map_Guj_Nat_Parks_Sanctuary.png
new file mode 100644
index 0000000..0482d8e
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Map_Guj_Nat_Parks_Sanctuary.png
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Mycenae_lion_gate_detail_dsc06384.jpg b/Processing/demolibrary/images/250px-Mycenae_lion_gate_detail_dsc06384.jpg
new file mode 100644
index 0000000..5978b1d
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Mycenae_lion_gate_detail_dsc06384.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Pride_of_lions.JPG b/Processing/demolibrary/images/250px-Pride_of_lions.JPG
new file mode 100644
index 0000000..e99ee11
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Pride_of_lions.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Serengeti_Lion_Running_saturated.jpg b/Processing/demolibrary/images/250px-Serengeti_Lion_Running_saturated.jpg
new file mode 100644
index 0000000..0f8ce9b
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Serengeti_Lion_Running_saturated.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Siberian_Tiger_sf.jpg b/Processing/demolibrary/images/250px-Siberian_Tiger_sf.jpg
new file mode 100644
index 0000000..e58eebc
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Siberian_Tiger_sf.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Tanzanian_Animals.jpg b/Processing/demolibrary/images/250px-Tanzanian_Animals.jpg
new file mode 100644
index 0000000..d176247
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Tanzanian_Animals.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Tiger_map.jpg b/Processing/demolibrary/images/250px-Tiger_map.jpg
new file mode 100644
index 0000000..f91c25e
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Tiger_map.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Tigerramki.jpg b/Processing/demolibrary/images/250px-Tigerramki.jpg
new file mode 100644
index 0000000..c220611
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Tigerramki.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Tipu_Sultan%27s_Tiger.JPG b/Processing/demolibrary/images/250px-Tipu_Sultan%27s_Tiger.JPG
new file mode 100644
index 0000000..18c42d1
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Tipu_Sultan%27s_Tiger.JPG
Binary files differ
diff --git a/Processing/demolibrary/images/250px-WalterRothschildWithZebras.jpg b/Processing/demolibrary/images/250px-WalterRothschildWithZebras.jpg
new file mode 100644
index 0000000..302dddb
--- /dev/null
+++ b/Processing/demolibrary/images/250px-WalterRothschildWithZebras.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Wiki_lion.jpg b/Processing/demolibrary/images/250px-Wiki_lion.jpg
new file mode 100644
index 0000000..3f0b106
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Wiki_lion.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/250px-Wildlifephotography.jpg b/Processing/demolibrary/images/250px-Wildlifephotography.jpg
new file mode 100644
index 0000000..6d1c072
--- /dev/null
+++ b/Processing/demolibrary/images/250px-Wildlifephotography.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/300px-Lascaux-diverticule-f%C3%A9lins.jpg b/Processing/demolibrary/images/300px-Lascaux-diverticule-f%C3%A9lins.jpg
new file mode 100644
index 0000000..78bba60
--- /dev/null
+++ b/Processing/demolibrary/images/300px-Lascaux-diverticule-f%C3%A9lins.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/300px-Namibie_Etosha_Girafe_01.jpg b/Processing/demolibrary/images/300px-Namibie_Etosha_Girafe_01.jpg
new file mode 100644
index 0000000..3cb11b1
--- /dev/null
+++ b/Processing/demolibrary/images/300px-Namibie_Etosha_Girafe_01.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/80px-India_tiger.jpg b/Processing/demolibrary/images/80px-India_tiger.jpg
new file mode 100644
index 0000000..f671bb5
--- /dev/null
+++ b/Processing/demolibrary/images/80px-India_tiger.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/83px-Indischer_Maler_um_1650_%28II%29_001.jpg b/Processing/demolibrary/images/83px-Indischer_Maler_um_1650_%28II%29_001.jpg
new file mode 100644
index 0000000..f3a89b2
--- /dev/null
+++ b/Processing/demolibrary/images/83px-Indischer_Maler_um_1650_%28II%29_001.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/84px-Brehms_Het_Leven_der_Dieren_Zoogdieren_Orde_4_Tijger_%28Felis_tigris%29.jpg b/Processing/demolibrary/images/84px-Brehms_Het_Leven_der_Dieren_Zoogdieren_Orde_4_Tijger_%28Felis_tigris%29.jpg
new file mode 100644
index 0000000..51e06f3
--- /dev/null
+++ b/Processing/demolibrary/images/84px-Brehms_Het_Leven_der_Dieren_Zoogdieren_Orde_4_Tijger_%28Felis_tigris%29.jpg
Binary files differ
diff --git a/Processing/demolibrary/images/97px-Sumatratiger-004.jpg b/Processing/demolibrary/images/97px-Sumatratiger-004.jpg
new file mode 100644
index 0000000..43a5c02
--- /dev/null
+++ b/Processing/demolibrary/images/97px-Sumatratiger-004.jpg
Binary files differ
diff --git a/Processing/demolibrary/lion-wikipedia.dita b/Processing/demolibrary/lion-wikipedia.dita
new file mode 100644
index 0000000..f7b73ff
--- /dev/null
+++ b/Processing/demolibrary/lion-wikipedia.dita
@@ -0,0 +1,2131 @@
+<?xml version='1.0' encoding='utf-8'?>
+<reference>
+ <title>
+ Lion
+ </title>
+ <shortdesc>
+ <ph id="2">
+ The lion (Panthera leo) is a member of the family Felidae and one of four big cats in the genus Panthera.
+ </ph>
+ <ph id="3">
+ With exceptionally large males exceeding 250 kg (550&amp;#160;lb) in weight, it is the second-largest living cat after the tiger.
+ </ph>
+ <ph id="4">
+ Wild lions currently exist in Sub-Saharan Africa and in Asia with a critically endangered remnant population in northwest India, having disappeared from North Africa, the Middle East, and Western Asia in historic times.
+ </ph>
+ <ph id="5">
+ Until the late Pleistocene (about 10,000&amp;#160;years ago), the lion was the most widespread large land mammal beside humans.
+ </ph>
+ <ph id="6">
+ They were found in most of Africa, much of Eurasia from western Europe to India and, in the Americas, from the Yukon to Peru.
+ </ph>
+ </shortdesc>
+ <prolog>
+ <source href="http://en.wikipedia.org/w/index.php?oldid=234379635">
+ <publisher>
+ wikipedia.org
+ </publisher>
+ <critdates>
+ <created date="2008-09-05">
+ <revised modified="2008-09-05">
+ </revised>
+ </created>
+ </critdates>
+ </source>
+ </prolog>
+ <refbody>
+ <section id="infobox">
+ <title>
+ Scientific classification
+ </title>
+ <properties>
+ <property>
+ <proptype>
+ Kingdom
+ </proptype>
+ <propvalue>
+ Animalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Phylum
+ </proptype>
+ <propvalue>
+ Chordata
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Class
+ </proptype>
+ <propvalue>
+ Mammalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Order
+ </proptype>
+ <propvalue>
+ Carnivora
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Family
+ </proptype>
+ <propvalue>
+ Felidae
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Genus
+ </proptype>
+ <propvalue>
+ Panthera
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Species
+ </proptype>
+ <propvalue>
+ P. leo
+ </propvalue>
+ </property>
+ </properties>
+ </section>
+ <p id="2">
+ <ph id="7">
+ Should they survive the rigors of cubhood, lionesses in secure habitat such as Kruger National Park may frequently reach an age of 12–14 years whereas lions seldom live for longer than 8 years.
+ </ph>
+ <ph id="8">
+ However, there are records of lionesses living for up to 20 years in the wild.
+ </ph>
+ <ph id="9">
+ In captivity both male and female lions can live for over 20 years.
+ </ph>
+ <ph id="10">
+ They typically inhabit savanna and grassland, although they may take to bush and forest.
+ </ph>
+ <ph id="11">
+ Lions are unusually social compared to other cats.
+ </ph>
+ <ph id="12">
+ A pride of lions consists of related females and offspring and a small number of adult males.
+ </ph>
+ <ph id="13">
+ Groups of female lions typically hunt together, preying mostly on large ungulates.
+ </ph>
+ <ph id="14">
+ The lion is an apex and keystone predator, although they will resort to scavenging if the opportunity arises.
+ </ph>
+ <ph id="15">
+ While lions, in general, do not selectively hunt humans, some have been known to become man-eaters and seek human prey.
+ </ph>
+ </p>
+ <p id="3">
+ <ph id="16">
+ The lion is a vulnerable species, having seen a possibly irreversible population decline of 30 to 50 percent over the past two decades in its African range; populations are untenable outside designated reserves and national parks.
+ </ph>
+ <ph id="17">
+ Although the cause of the decline is not well understood, habitat loss and conflicts with humans are currently the greatest causes of concern.
+ </ph>
+ <ph id="18">
+ Lions have been kept in menageries since Roman times and have been a key species sought after and exhibited in zoos the world over since the late eighteenth century.
+ </ph>
+ <ph id="19">
+ Zoos are cooperating worldwide in breeding programs for the endangered Asiatic subspecies.
+ </ph>
+ </p>
+ <p id="4">
+ <ph id="20">
+ Visually, the male is highly distinctive and is easily recognized by its mane.
+ </ph>
+ <ph id="21">
+ The head of the male lion is one of the most widely recognized animal symbols in human culture.
+ </ph>
+ <ph id="22">
+ It has been depicted extensively in literature, in sculptures, in paintings, on national flags, and in contemporary films and literature.
+ </ph>
+ </p>
+ <p id="5">
+ <ph id="23">
+ The lioness has been recognized, however, as the pinnacle of hunting prowess from the earliest of human writings and graphic representations.
+ </ph>
+ <ph id="24">
+ The lionesses are the hunters for their pride and capture their prey with precise and complex teamwork.
+ </ph>
+ <ph id="25">
+ Each lioness develops specific skills for her role in the hunting techniques used by her pride and, generally, assumes that role during most hunts.
+ </ph>
+ <ph id="26">
+ Members of human cultures living among lions in natural habitats have understood this characteristic and often have chosen the lioness to represent their most ferocious war deities and warriors, often naming their male rulers as her "son".
+ </ph>
+ <ph id="27">
+ Examples drawn from the earliest of written records include the Egyptian pantheon deities of Sekhmet, Bast, Menhit, and Tefnut, and these deities may have had precursors in Nubia and Lybia.
+ </ph>
+ <ph id="28">
+ Other Egyptian deities are quite complex and assume aspects that may include one as a lioness headed human or a lioness in specific roles.
+ </ph>
+ <ph id="29">
+ Depictions of lions hunting in groups have existed from the Upper Paleolithic period, with carvings and paintings from the Lascaux and Chauvet Caves.
+ </ph>
+ </p>
+ <p id="6">
+ <ph id="30">
+ </ph>
+ </p>
+ </refbody>
+ <reference id="2">
+ <title>
+ Naming and etymology
+ </title>
+ <refbody>
+ <p id="7">
+ <ph id="31">
+ The lion's name, similar in many Romance languages, derives from the Latin leo; cf.
+ </ph>
+ <ph id="32">
+ the Ancient Greek λέων (leon).
+ </ph>
+ <ph id="33">
+ The Hebrew word lavi (לָבִיא) may also be related, as well as the Ancient Egyptian rw.
+ </ph>
+ <ph id="34">
+ It was one of the many species originally described, as Felis leo, by Linnaeus in his eighteenth&amp;#160;century work, Systema Naturae.
+ </ph>
+ <ph id="35">
+ The generic component of its scientific designation, Panthera leo, is often presumed to derive from Greek pan- ("all") and ther ("beast"), but this may be a folk etymology.
+ </ph>
+ <ph id="36">
+ Although it came into English through the classical languages, panthera is probably of East Asian origin, meaning "the yellowish animal,"
+ </ph>
+ <ph id="37">
+ or "whitish-yellow".
+ </ph>
+ </p>
+ <p id="8">
+ <ph id="38">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="3">
+ <title>
+ Taxonomy and evolution
+ </title>
+ <refbody>
+ <p id="9">
+ <ph id="39">
+ The oldest lion-like fossil is known from Laetoli in Tanzania and is perhaps 3.5&amp;#160;million years old; some scientists have identified the material as Panthera leo.
+ </ph>
+ <ph id="40">
+ These records are not well-substantiated, and all that can be said is that they pertain to a Panthera-like felid.
+ </ph>
+ <ph id="41">
+ The oldest confirmed records of Panthera leo in Africa are about 2&amp;#160;million years younger.
+ </ph>
+ <ph id="42">
+ The closest relatives of the lion are the other Panthera species: the tiger, the jaguar, and the leopard.
+ </ph>
+ <ph id="43">
+ Morphological and genetic studies reveal that the tiger was the first of these recent species to diverge.
+ </ph>
+ <ph id="44">
+ About 1.9&amp;#160;million years ago the jaguar branched off the remaining group, which contained ancestors of the leopard and lion.
+ </ph>
+ <ph id="45">
+ The lion and leopard subsequently separated about 1 to 1.25&amp;#160;million years ago from each other.
+ </ph>
+ </p>
+ <p id="10">
+ <ph id="46">
+ Panthera leo itself evolved in Africa between 1 million and 800,000 years ago before spreading throughout the Holarctic region.
+ </ph>
+ <ph id="47">
+ It appeared in Europe for the first time 700,000 years ago with the subspecies Panthera leo fossilis at Isernia in Italy.
+ </ph>
+ <ph id="48">
+ From this lion derived the later Cave Lion (Panthera leo spelaea), which appeared about 300,000 years ago.
+ </ph>
+ <ph id="49">
+ During the upper Pleistocene the lion spread to North and South America, and developed into Panthera leo atrox, the American Lion.
+ </ph>
+ <ph id="50">
+ Lions died out in northern Eurasia and America at the end of the last glaciation, about 10,000 years ago; this may have been secondary to the extinction of Pleistocene megafauna.
+ </ph>
+ </p>
+ <p id="11">
+ <ph id="51">
+ </ph>
+ </p>
+ <section id="2">
+ <title>
+ Subspecies
+ </title>
+ <p id="12">
+ <ph id="52">
+ Traditionally 12 recent subspecies of lion were recognized, the largest of which has been recognized as the Barbary Lion.
+ </ph>
+ <ph id="53">
+ The major differences between these subspecies are location, mane appearance, size, and distribution.
+ </ph>
+ <ph id="54">
+ Because these characteristics are very insignificant and show a high individual variability, most of these forms were debatable and probably invalid; additionally, they were often based upon zoo material of unknown origin that may have had "striking, but abnormal"
+ </ph>
+ <ph id="55">
+ morphological characteristics.
+ </ph>
+ <ph id="56">
+ Today only eight subspecies are usually accepted, but one of these (the Cape Lion formerly described as Panthera leo melanochaita) is probably invalid.
+ </ph>
+ <ph id="57">
+ Even the remaining seven subspecies might be too much; mitochondrial variation in recent African lions is modest, which suggests that all Sub-Saharan lions could be considered a single subspecies, possibly divided in two main clades: one to the west of the Great Rift Valley and the other to the east.
+ </ph>
+ <ph id="58">
+ Lions from Tsavo in Eastern Kenya are much closer genetically to lions in Transvaal (South Africa), than to those in the Aberdare Range in Western Kenya.
+ </ph>
+ </p>
+ <p id="13">
+ <ph id="59">
+ </ph>
+ </p>
+ </section>
+ <section id="3">
+ <title>
+ Recent
+ </title>
+ <p id="14">
+ <ph id="60">
+ Eight recent subspecies are recognized today:
+ </ph>
+ </p>
+ <ul>
+ <li>
+ P. l. persica, known as the Asiatic Lion or South Asian, Persian, or Indian lion, was once widespread from Turkey, across the Middle East, to Pakistan, India, and even Bangladesh. However, large prides and daylight activity made it easier to poach than tigers or leopards; now around 300 exist in and near the Gir Forest of India.
+ </li>
+ <li>
+ P. l. leo, known as the Barbary Lion, is extinct in the wild due to excessive hunting, although captive individuals may still exist. This was one of the largest of the lion subspecies, at approximately 3–3.5 metres (10–11.5&amp;#160;ft) long and weighing over 150&amp;#160;kilograms (330&amp;#160;lb). They ranged from Morocco to Egypt. The last wild Barbary Lion was killed in Morocco in 1922.
+ </li>
+ <li>
+ P. l. senegalensis, known as the West African lion, is found in Western Africa, from Senegal to Nigeria.
+ </li>
+ <li>
+ P. l. azandica, known as the North East Congo lion, is found in the North-eastern parts of the Congo.
+ </li>
+ <li>
+ P. l. nubica, known as the East African Lion or Massai lion, is found in East Africa, from Ethiopia and Kenya to Tanzania and Mozambique.
+ </li>
+ <li>
+ P. l. bleyenberghi, known as the Southwest African lion or Katanga lion. It is found in South-western Africa, Namibia, Botswana, Angola, Katanga (Zaire), Zambia, and Zimbabwe.
+ </li>
+ <li>
+ P. l. krugeri, known as the Southeast African lion or Transvaal lion, is found in the Transvaal region of South eastern Africa, including Kruger National Park.
+ </li>
+ <li>
+ P. l. melanochaita, known as the Cape Lion, became extinct in the wild around 1860. Results of mitochondrial DNA research do not support the status as a distinct subspecies. It seems probable that the Cape lion was only the southernmost population of the extant southern African lion.
+ </li>
+ </ul>
+ <p id="15">
+ <ph id="61">
+ </ph>
+ </p>
+ </section>
+ <section id="4">
+ <title>
+ Prehistoric
+ </title>
+ <p id="16">
+ <ph id="62">
+ Several additional subspecies of lion existed in prehistoric times:
+ </ph>
+ </p>
+ <ul>
+ <li>
+ P. l. atrox, known as the American Lion or American cave lion, was abundant in the Americas from Alaska to Peru in the Pleistocene Epoch until about 10,000 years ago. This form as well as the cave lion are sometimes considered to represent separate species, but recent phylogenetic studies suggest that they are in fact subspecies of the lion (Panthera leo). One of the largest lion subspecies to have existed, its body length is estimated to have been 1.6–2.5&amp;#160;m (5–8&amp;#160;ft).
+ </li>
+ <li>
+ P. l. fossilis, known as the Early Middle Pleistocene European cave lion, flourished about 500,000 years ago; fossils have been recovered from Germany and Italy.
+ </li>
+ <li>
+ P. l. spelaea, known as the European cave lion, Eurasian cave lion, or Upper Pleistocene European cave lion, occurred in Eurasia 300,000 to 10,000 years ago. This species is known from Paleolithic cave paintings (such as the one displayed to the right), ivory carvings, and clay busts, indicating it had protruding ears, tufted tails, perhaps faint tiger-like stripes, and that at least some males had a ruff or primitive mane around their necks. With this example being a hunting scene it is likely that it depicts females hunting for the pride using the same strategy as their contemporary relatives and males may not be part of the subject.
+ </li>
+ <li>
+ P. l. vereshchagini, known as the East Siberian- or Beringian cave lion, was found in Yakutia (Russia), Alaska (USA), and the Yukon Territory (Canada). Analysis of skulls and mandibles of this lion demonstrate that it is distinct—larger than the European cave lion and smaller than the American cave lion with differing skull proportions.
+ </li>
+ </ul>
+ <p id="17">
+ <ph id="63">
+ </ph>
+ </p>
+ </section>
+ <section id="5">
+ <title>
+ Dubious
+ </title>
+ <ul>
+ <li>
+ P. l. sinhaleyus, known as the Sri Lanka Lion, appears to have become extinct around 39,000 years ago. It is only known from two teeth found in deposits at Kuruwita. Based on these teeth, P. Deraniyagala erected this subspecies in 1939.
+ </li>
+ <li>
+ P. l. europaea, known as the European Lion, was probably identical with Panthera leo persica or Panthera leo spelea; its status as a subspecies is unconfirmed. It became extinct around 100 AD due to persecution and over-exploitation. It inhabited the Balkans, the Italian Peninsula, southern France and the Iberian Peninsula. It was a very popular object of hunting among Romans, Greeks, and Macedonians.
+ </li>
+ <li>
+ P. l. youngi or Panthera youngi , known as the North-Eastern Pleistocene China cave lion, flourished 350,000 years ago. Its relationship to the extant lion subspecies is obscure, and it probably represents a distinct species.
+ </li>
+ <li>
+ P. l. maculatus, known as the Marozi or Spotted lion, is sometimes believed to be a distinct subspecies, but may be an adult lion that has retained its juvenile spotted pattern. If it was a subspecies in its own right, rather than a small number of aberrantly colored individuals, it has been extinct since 1931. A less likely identity is a natural leopard/lion hybrid commonly known as a leopon.
+ </li>
+ </ul>
+ <p id="18">
+ <ph id="64">
+ </ph>
+ </p>
+ </section>
+ <section id="6">
+ <title>
+ Hybrids
+ </title>
+ <p id="19">
+ <ph id="65">
+ Lions have been known to breed with tigers (most often the Siberian and Bengal subspecies) to create hybrids called ligers and tigons.
+ </ph>
+ <ph id="66">
+ They have also been crossed with leopards to produce leopons, and jaguars to produce jaglions.
+ </ph>
+ <ph id="67">
+ The marozi is reputedly a spotted lion or a naturally occurring leopon, while the Congolese Spotted Lion is a complex lion/jaguar/leopard hybrid called a lijagulep.
+ </ph>
+ <ph id="68">
+ Such hybrids were once commonly bred in zoos, but this is now discouraged due to the emphasis on conserving species and subspecies.
+ </ph>
+ <ph id="69">
+ Hybrids are still bred in private menageries and in zoos in China.
+ </ph>
+ </p>
+ <p id="20">
+ <ph id="70">
+ The liger is a cross between a male lion and a tigress.
+ </ph>
+ <ph id="71">
+ Because the growth-inhibiting gene from the female tiger is absent for a growth-promoting gene passed on by the male lion, ligers grow far larger than either parent.
+ </ph>
+ <ph id="72">
+ They share physical and behavioural qualities of both parent species (spots and stripes on a sandy background).
+ </ph>
+ <ph id="73">
+ Male ligers are sterile, but female ligers are often fertile.
+ </ph>
+ <ph id="74">
+ Males have about a 50 percent chance of having a mane, but if they grow one their manes will be modest: around 50 percent of a pure lion mane.
+ </ph>
+ <ph id="75">
+ Ligers are typically between 3.0 and 3.7&amp;#160;m (10 to 12 feet) in length, and can be between 360 and 450&amp;#160;kg (800 to 1,000 pounds) or more.
+ </ph>
+ <ph id="76">
+ The less common tigon is a cross between the lioness and the male tiger.
+ </ph>
+ </p>
+ <p id="21">
+ <ph id="77">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="4">
+ <title>
+ Physical characteristics
+ </title>
+ <refbody>
+ <p id="22">
+ <ph id="78">
+ The lion is the second largest feline after the tiger.
+ </ph>
+ <ph id="79">
+ With powerful legs, a strong jaw, and 8&amp;#160;cm (3.1&amp;#160;in) long canine teeth, the lion can bring down and kill large prey.
+ </ph>
+ <ph id="80">
+ Lion coloration varies from light buff to yellowish, reddish or dark ochraceous brown.
+ </ph>
+ <ph id="81">
+ The underparts are generally lighter and the tail tuft is black.
+ </ph>
+ <ph id="82">
+ Lion cubs are born with brown rosettes (spots) on their body, rather like those of a leopard.
+ </ph>
+ <ph id="83">
+ Although these fade as lions reach adulthood, faint spots can still often be seen on the legs and underparts, particularly on lionesses.
+ </ph>
+ </p>
+ <p id="23">
+ <ph id="84">
+ Lions are the only members of the cat family to display obvious sexual dimorphism—that is, males and females look distinctly different, as a consequence of the specialized roles that each play in the pride.
+ </ph>
+ <ph id="85">
+ For instance, the lioness, as the hunter, lacks the male's thick mane, which would impede her ability to camouflage when stalking the prey.
+ </ph>
+ <ph id="86">
+ The color of the male's mane varies from blond to black, generally becoming darker as the lion grows older.
+ </ph>
+ </p>
+ <p id="24">
+ <ph id="87">
+ Weights for adult lions generally lie between 150–227&amp;#160;kg (330–500&amp;#160;lb) for males, and 123–182&amp;#160;kg (270–400&amp;#160;lb) for females.
+ </ph>
+ <ph id="88">
+ Nowell and Jackson report average weights of 181&amp;#160;kg for males and 126&amp;#160;kg for females; one male shot near Mount Kenya was weighed at 272&amp;#160;kg (600&amp;#160;lb).
+ </ph>
+ <ph id="89">
+ Lions tend to vary in size depending on their environment and area, resulting in a wide spread in recorded weights.
+ </ph>
+ <ph id="90">
+ For instance, lions in southern Africa tend to be about 5 percent heavier than those in East Africa, in general.
+ </ph>
+ </p>
+ <p id="25">
+ <ph id="91">
+ Head and body length is 170–250&amp;#160;cm (5&amp;#160;ft 7&amp;#160;in – 8&amp;#160;ft 2&amp;#160;in) in males and 140–175&amp;#160;cm (4&amp;#160;ft 7&amp;#160;in – 5&amp;#160;ft 9&amp;#160;in) in females; shoulder height is about 121&amp;#160;cm (4&amp;#160;ft) in males and 98&amp;#160;cm (3&amp;#160;ft 3&amp;#160;in) in females.
+ </ph>
+ <ph id="92">
+ The tail length is 70–100&amp;#160;cm (2&amp;#160;ft 3&amp;#160;in – 3&amp;#160;ft 3&amp;#160;in).
+ </ph>
+ <ph id="93">
+ The longest known lion was a black-maned male shot near Mucsso, southern Angola in October 1973; the heaviest known lion was a man-eater shot in 1936 just outside Hectorspruit in eastern Transvaal, South Africa and weighed 313 kg (690 lb).
+ </ph>
+ <ph id="94">
+ Lions in captivity tend to be larger than lions in the wild—the heaviest lion on record is a male at Colchester Zoo in England named Simba in 1970, who weighed in at 375 kg (826 lb).
+ </ph>
+ </p>
+ <p id="26">
+ <ph id="95">
+ In both males and females, the tail ends in a hairy tuft.
+ </ph>
+ <ph id="96">
+ In some lions, the tuft conceals a hard "spine"
+ </ph>
+ <ph id="97">
+ or "spur", approximately 5&amp;#160;mm long, formed of the final sections of tail bone fused together.
+ </ph>
+ <ph id="98">
+ The lion is the only felid to have a tufted tail—the function of the tuft and spine are unknown.
+ </ph>
+ <ph id="99">
+ Absent at birth, the tuft develops around 5½&amp;#160;months of age and is readily identifiable at 7&amp;#160;months.
+ </ph>
+ </p>
+ <p id="27">
+ <ph id="100">
+ </ph>
+ </p>
+ <section id="7">
+ <title>
+ Mane
+ </title>
+ <p id="28">
+ <ph id="101">
+ The mane of the male lion, unique amongst cats, is one of the most distinctive characteristics of the species.
+ </ph>
+ <ph id="102">
+ It makes the lion appear larger, providing an excellent intimidation display; this aids the lion during confrontations with other lions and with the species' chief competitor in Africa, the spotted hyena.
+ </ph>
+ <ph id="103">
+ The presence, absence, color, and size of the mane is associated with genetic precondition, sexual maturity, climate and testosterone production; the rule of thumb is the darker and fuller the mane, the healthier the lion.
+ </ph>
+ <ph id="104">
+ Research in Tanzania also suggests mane length signals fighting success in male-male relationships.
+ </ph>
+ <ph id="105">
+ Darker-maned individuals may have longer reproductive lives and higher offspring survival, although they suffer in the hottest months of the year.
+ </ph>
+ <ph id="106">
+ In prides including a coalition of two or three males, it is possible that lionesses solicit mating more actively with heavily maned lions.
+ </ph>
+ </p>
+ <p id="29">
+ <ph id="107">
+ Scientists once believed that the distinct status of some subspecies could be justified by morphology, including the size of the mane.
+ </ph>
+ <ph id="108">
+ Morphology was used to identify subspecies such as the Barbary Lion and Cape Lion.
+ </ph>
+ <ph id="109">
+ Research has suggested, however, that environmental factors influence the color and size of a lion's mane, such as the ambient temperature.
+ </ph>
+ <ph id="110">
+ The cooler ambient temperature in European and North American zoos, for example, can result in a heavier mane.
+ </ph>
+ <ph id="111">
+ Thus the mane is an inappropriate marker for identifying subspecies.
+ </ph>
+ <ph id="112">
+ However the males of the Asiatic subspecies are characterized by sparser manes than average African lions.
+ </ph>
+ </p>
+ <p id="30">
+ <ph id="113">
+ Maneless male lions have been reported in Senegal and Tsavo East National Park in Kenya, and the original male white lion from Timbavati also was maneless.
+ </ph>
+ <ph id="114">
+ Castrated lions have minimal manes.
+ </ph>
+ <ph id="115">
+ The lack of a mane is sometimes found in inbred lion populations; inbreeding also results in poor fertility.
+ </ph>
+ </p>
+ <p id="31">
+ <ph id="116">
+ Many lionesses have a ruff that may be apparent in certain poses.
+ </ph>
+ <ph id="117">
+ Sometimes it is indicated in sculptures and drawings, especially ancient artwork, and is misinterpreted as a male mane.
+ </ph>
+ <ph id="118">
+ It differs from a mane, however, in being at the jaw line below the ears, of much less hair length, and frequently not noticeable, whereas a mane extends above the ears, often obscuring their outline entirely.
+ </ph>
+ </p>
+ <p id="32">
+ <ph id="119">
+ Cave paintings of extinct European Cave Lions exclusively show animals with no mane, or just the hint of a mane, suggesting to some that they were more or less maneless; however, females hunting for a pride are the likely subjects of the drawings—since they are shown in a group related to hunting—so these images do not enable a reliable judgment about whether the males had manes.
+ </ph>
+ <ph id="120">
+ The drawings do suggest that the extinct species used the same social organization and hunting strategies as contemporary lions.
+ </ph>
+ </p>
+ <p id="33">
+ <ph id="121">
+ </ph>
+ </p>
+ </section>
+ <section id="8">
+ <title>
+ White lions
+ </title>
+ <p id="34">
+ <ph id="122">
+ The white lion is not a distinct subspecies, but a special morph with a genetic condition, leucism, that causes paler colouration akin to that of the white tiger; the condition is similar to melanism, which causes black panthers.
+ </ph>
+ <ph id="123">
+ White Transvaal lion (Panthera leo krugeri) individuals occasionally have been encountered in and around Kruger National Park and the adjacent Timbavati Private Game Reserve in eastern South Africa, but are more commonly found in captivity, where breeders deliberately select them.
+ </ph>
+ <ph id="124">
+ The unusual cream color of their coats is due to a recessive gene.
+ </ph>
+ <ph id="125">
+ Reportedly, they have been bred in camps in South Africa for use as trophies for canned hunts.
+ </ph>
+ </p>
+ <p id="35">
+ <ph id="126">
+ Confirmation of the existence of white lions only came in the late twentieth century.
+ </ph>
+ <ph id="127">
+ For hundreds of years prior, the white lion had been thought to be a figment of legend circulating in South Africa, the white pelage of the animal said to represent the goodness in all creatures.
+ </ph>
+ <ph id="128">
+ Sightings were first reported in the early 1900s, and continued, infrequently, for almost fifty years until, in 1975, a litter of white lion cubs was found at Timbavati Game Reserve.
+ </ph>
+ </p>
+ <p id="36">
+ <ph id="129">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="5">
+ <title>
+ Biology and behavior
+ </title>
+ <refbody>
+ <p id="37">
+ <ph id="130">
+ Lions spend much of their time resting and are inactive for about 20&amp;#160;hours per day.
+ </ph>
+ <ph id="131">
+ Although lions can be active at any time, their activity generally peaks after dusk with a period of socializing, grooming and defecating.
+ </ph>
+ <ph id="132">
+ Intermittent bursts of activity follow through the night hours to dawn, when hunting most often takes place.
+ </ph>
+ <ph id="133">
+ They spend an average of two hours a day walking and 50&amp;#160;minutes eating.
+ </ph>
+ </p>
+ <p id="38">
+ <ph id="134">
+ </ph>
+ </p>
+ <section id="9">
+ <title>
+ Group organization
+ </title>
+ <p id="39">
+ <ph id="135">
+ Lions are predatory carnivores who manifest two types of social organization.
+ </ph>
+ <ph id="136">
+ Some are residents, living in groups, called prides.
+ </ph>
+ <ph id="137">
+ The pride usually consists of approximately five or six related females, their cubs of both sexes, and one or two males known as a coalition who mate with the adult females (although extremely large prides, consisting of up to 30 individuals, have been observed).
+ </ph>
+ <ph id="138">
+ The coalition of males associated with a pride are usually two, but may increase to four and decrease again over time.
+ </ph>
+ <ph id="139">
+ Male cubs are excluded from their maternal pride when they reach maturity.
+ </ph>
+ </p>
+ <p id="40">
+ <ph id="140">
+ The second organizational behaviour is labeled nomads, who range widely and move about sporadically, either singularly or in pairs.
+ </ph>
+ <ph id="141">
+ Pairs are more frequent among related males who have been excluded from their birth pride.
+ </ph>
+ <ph id="142">
+ Note that a lion may switch lifestyles; nomads may become residents and vice versa.
+ </ph>
+ <ph id="143">
+ Males have to go through this lifestyle and some never are able to join another pride.
+ </ph>
+ <ph id="144">
+ A female who becomes a nomad has much greater difficulty joining a new pride, as the females in a pride are related and reject most attempts by an unrelated female to join their family group.
+ </ph>
+ </p>
+ <p id="41">
+ <ph id="145">
+ The area a pride occupies is called a pride area, whereas that by a nomad is a range.
+ </ph>
+ <ph id="146">
+ The males associated with a pride tend to stay on the fringes, patrolling their territory.
+ </ph>
+ <ph id="147">
+ Why sociality—the most pronounced in any cat species—has developed in lionesses is the subject of much debate.
+ </ph>
+ <ph id="148">
+ Increased hunting success appears an obvious reason, but this is less than sure upon examination: coordinated hunting does allow for more successful predation, but also ensures that non-hunting "cheaters"
+ </ph>
+ <ph id="149">
+ reduce per capita caloric intake.
+ </ph>
+ <ph id="150">
+ Other benefits include possible kin selection (better to share food with a related lion than with a stranger), protection of the young, maintenance of territory, and individual insurance against injury and hunger.
+ </ph>
+ </p>
+ <p id="42">
+ <ph id="151">
+ Lionesses do the majority of the hunting for their pride, being smaller, swifter and more agile than the males, and unencumbered by the heavy and conspicuous mane, which causes overheating during exertion.
+ </ph>
+ <ph id="152">
+ They act as a co-ordinated group in order to successfully stalk and bring down the prey.
+ </ph>
+ <ph id="153">
+ However, males have a tendency to dominate the kill once the lionesses have succeeded (they are actually more likely to share the kill with the cubs than with the lionesses), and rarely share food they have killed by themselves.
+ </ph>
+ <ph id="154">
+ Smaller prey is eaten at the location of the hunt, thereby being shared among the hunters; when the kill is larger it often is dragged to the pride area.
+ </ph>
+ <ph id="155">
+ There is more sharing with larger kills, although pride members still often behave aggressively towards each other as they each try to consume as much food as they can.
+ </ph>
+ </p>
+ <p id="43">
+ <ph id="156">
+ Both males and females defend the pride against intruders.
+ </ph>
+ <ph id="157">
+ Some individual lions consistently lead the defense against intruders, while others lag behind.
+ </ph>
+ <ph id="158">
+ These "laggards"
+ </ph>
+ <ph id="159">
+ are not punished by leaders.
+ </ph>
+ <ph id="160">
+ Possibly laggards provide other services to the group so that leaders forgive them.
+ </ph>
+ <ph id="161">
+ An alternative hypothesis is that there is some reward associated with being a leader who fends off intruders.
+ </ph>
+ <ph id="162">
+ The male or males often defend the pride from outside males who attempt to take over the pride.
+ </ph>
+ <ph id="163">
+ Females form a stable social unit in a pride and do not tolerate outside females; membership only changes with the births and deaths of lionesses, though some females do leave and become nomadic.
+ </ph>
+ <ph id="164">
+ Subadult males on the other hand, leave the pride when they reach maturity at around 2–3 years of age.
+ </ph>
+ </p>
+ <p id="44">
+ <ph id="165">
+ </ph>
+ </p>
+ </section>
+ <section id="10">
+ <title>
+ Hunting and diet
+ </title>
+ <p id="45">
+ <ph id="166">
+ Lions are powerful animals who usually hunt in coordinated groups and stalk their chosen prey.
+ </ph>
+ <ph id="167">
+ However, they are not particularly known for their stamina - for instance, a lioness' heart makes up only 0.57 percent of her body weight (a male's is 0.45 percent of his body weight), whereas a hyena's heart is close to 10 percent of its body weight.
+ </ph>
+ <ph id="168">
+ Thus, although lionesses can reach speeds of 59&amp;#160;km/h (40&amp;#160;mph), they can only do so for short bursts so they have to be close to their prey before starting the attack.
+ </ph>
+ <ph id="169">
+ They take advantage of factors that reduce visibility; many kills take place near some form of cover or at night.
+ </ph>
+ <ph id="170">
+ They sneak up to the victim until they reach a distance of approximately 30&amp;#160;metres (98 ft) or less.
+ </ph>
+ <ph id="171">
+ Typically, several female lions work together and encircle the herd from different points.
+ </ph>
+ <ph id="172">
+ Once they have closed with a herd, they usually target the closest prey.
+ </ph>
+ <ph id="173">
+ The attack is short and powerful; they attempt to catch the victim with a fast rush and final leap.
+ </ph>
+ <ph id="174">
+ The prey usually is killed by strangulation.
+ </ph>
+ </p>
+ <p id="46">
+ <ph id="175">
+ The prey consists mainly of large mammals, with a preference for wildebeest, impalas, zebras, buffalo, and warthogs in Africa and nilgai, wild boar, and several deer species in India.
+ </ph>
+ <ph id="176">
+ Many other species are hunted, based on availability.
+ </ph>
+ <ph id="177">
+ Mainly this will include ungulates weighing between 50 and 300 kg (110–660&amp;#160;lb) such as kudu, hartebeest, gemsbok, and eland.
+ </ph>
+ <ph id="178">
+ Occasionally, they take relatively small species such as Thomson's Gazelle or springbok.
+ </ph>
+ <ph id="179">
+ Lions living near the Namib coast feed extensively on seals.
+ </ph>
+ <ph id="180">
+ Lions hunting in groups are capable of taking down most animals, even healthy adults, but they rarely attack very large prey such as buffalo bulls or fully grown male giraffes due to the danger of injury.
+ </ph>
+ </p>
+ <p id="47">
+ <ph id="181">
+ Extensive statistics collected over various studies show that lions normally feed on mammals in the range 190–550 kg (420–1210&amp;#160;lb).
+ </ph>
+ <ph id="182">
+ Wildebeest rank at the top of peferred prey (making nearly half of the lion prey in the Serengeti) followed by zebra.
+ </ph>
+ <ph id="183">
+ Most adult hippopotamuses, rhinoceroses, elephants, and smaller gazelles, impala, and other agile antelopes are generally excluded.
+ </ph>
+ <ph id="184">
+ However giraffes, and buffalos are often taken in certain regions.
+ </ph>
+ <ph id="185">
+ Occasionally hippopotamus is also taken, but adult rhinoceroses are generally avoided.
+ </ph>
+ <ph id="186">
+ Even though smaller than 190 kg (420&amp;#160;lb), warthogs are often taken depending on availability.
+ </ph>
+ <ph id="187">
+ In some areas, they specialise in hunting atypical prey species; this is the case at the Savuti river, where they prey on elephants.
+ </ph>
+ <ph id="188">
+ Park guides in the area reported that the lions, driven by extreme hunger, started taking down baby elephants, and then moved on to adolescents and, occasionally, fully grown adults during the night when elephants' vision is poor.
+ </ph>
+ <ph id="189">
+ In Kruger National Park, giraffes are regularly hunted.
+ </ph>
+ <ph id="190">
+ Lions also attack domestic livestock; in India cattle contribute significantly to their diet.
+ </ph>
+ <ph id="191">
+ They are capable of killing other predators such as leopards, cheetahs, hyenas, and wild dogs, as well as scavenging animals either dead from natural causes or killed by other predators.
+ </ph>
+ <ph id="192">
+ A lion may gorge itself and eat up to 30&amp;#160;kg (66&amp;#160;lb) in one sitting; if it is unable to consume all the kill it will rest for a few hours before consuming more.
+ </ph>
+ <ph id="193">
+ On a hot day, the pride may retreat to shade leaving a male or two to stand guard.
+ </ph>
+ <ph id="194">
+ An adult lioness requires an average of about 5&amp;#160;kg (11&amp;#160;lb) of meat per day, a male about 7&amp;#160;kg (15.4&amp;#160;lb).
+ </ph>
+ </p>
+ <p id="48">
+ <ph id="195">
+ Because lionesses hunt in open spaces where they are easily seen by their prey, cooperative hunting increases the likelihood of a successful hunt; this is especially true with larger species.
+ </ph>
+ <ph id="196">
+ Teamwork also enables them to defend their kills more easily against other large predators such as hyenas, which may be attracted by vultures from kilometers away in open savannas.
+ </ph>
+ <ph id="197">
+ Lionesses do most of the hunting.
+ </ph>
+ <ph id="198">
+ In typical hunts, each lioness has a favored position in the group, either stalking prey on the "wing"
+ </ph>
+ <ph id="199">
+ then attacking, or moving a smaller distance in the centre of the group and capturing prey in flight from other lionesses.
+ </ph>
+ </p>
+ <p id="49">
+ <ph id="200">
+ Males attached to prides do not usually participate in hunting, except in the case of larger quarry such as giraffe and buffalo.
+ </ph>
+ <ph id="201">
+ Bachelor male lions without a pride of their own are forced to hunt.
+ </ph>
+ <ph id="202">
+ Male lions have also been observed and recorded hunting in groups.
+ </ph>
+ </p>
+ <p id="50">
+ <ph id="203">
+ Young lions first display stalking behavior around three months of age, although they do not participate in hunting until they are almost a year old.
+ </ph>
+ <ph id="204">
+ They begin to hunt effectively when nearing the age of two.
+ </ph>
+ <ph id="205">
+ Depending upon how quickly they mature, males are excluded from the pride at age two or three.
+ </ph>
+ </p>
+ <p id="51">
+ <ph id="206">
+ </ph>
+ </p>
+ </section>
+ <section id="11">
+ <title>
+ Reproduction and life cycle
+ </title>
+ <p id="52">
+ <ph id="207">
+ Most lionesses will have reproduced by the time they are four years of age.
+ </ph>
+ <ph id="208">
+ Lions do not mate at any specific time of year, and the females are polyestrous.
+ </ph>
+ <ph id="209">
+ As with other cats, the male lion's penis has spines which point backwards.
+ </ph>
+ <ph id="210">
+ Upon withdrawal of the penis, the spines rake the walls of the female's vagina, which may cause ovulation.
+ </ph>
+ <ph id="211">
+ A lioness may mate with more than one male when she is in heat; during a mating bout, which could last several days, the couple copulates twenty to forty times a day and are likely to forgo eating.
+ </ph>
+ <ph id="212">
+ Lions reproduce very well in captivity.
+ </ph>
+ </p>
+ <p id="53">
+ <ph id="213">
+ The average gestation period is around 110&amp;#160;days, the female giving birth to a litter of one to four cubs in a secluded den (which may be a thicket, a reed-bed, a cave or some other sheltered area) usually away from the rest of the pride.
+ </ph>
+ <ph id="214">
+ She will often hunt by herself whilst the cubs are still helpless, staying relatively close to the thicket or den where the cubs are kept.
+ </ph>
+ <ph id="215">
+ The cubs themselves are born blind—their eyes do not open until roughly a week after birth.
+ </ph>
+ <ph id="216">
+ They weigh 1.2–2.1&amp;#160;kg (2.6–4.6&amp;#160;lb) at birth and are almost helpless, beginning to crawl a day or two after birth and walking around three weeks of age.
+ </ph>
+ <ph id="217">
+ The lioness moves her cubs to a new den site several times a month, carrying them one by one by the nape of the neck, to prevent scent from building up at a single den site and thus avoiding the attention of predators that may harm the cubs.
+ </ph>
+ </p>
+ <p id="54">
+ <ph id="218">
+ Usually, the mother does not integrate herself and her cubs back into the pride until the cubs are six to eight weeks old.
+ </ph>
+ <ph id="219">
+ However, sometimes this introduction to pride life occurs earlier, particularly if other lionesses have given birth at about the same time.
+ </ph>
+ <ph id="220">
+ For instance, lionesses in a pride often synchronize their reproductive cycles so that they cooperate in the raising and suckling of the young (once the cubs are past the initial stage of isolation with their mother), who suckle indiscriminately from any or all of the nursing females in the pride.
+ </ph>
+ <ph id="221">
+ In addition to greater protection, the synchronization of births also has an advantage in that the cubs end up being roughly the same size, and thus have an equal chance of survival.
+ </ph>
+ <ph id="222">
+ If one lioness gives birth to a litter of cubs a couple of months after another lioness, for instance, then the younger cubs, being much smaller than their older brethren, are usually dominated by larger cubs at mealtimes—consequently, death by starvation is more common amongst the younger cubs.
+ </ph>
+ </p>
+ <p id="55">
+ <ph id="223">
+ In addition to starvation, cubs also face many other dangers, such as predation by jackals, hyenas, leopards, martial eagles and snakes.
+ </ph>
+ <ph id="224">
+ Even buffaloes, should they catch the scent of lion cubs, often stampede towards the thicket or den where they are being kept, doing their best to trample the cubs to death whilst warding off the lioness.
+ </ph>
+ <ph id="225">
+ Furthermore, when one or more new males oust the previous male(s) associated with a pride, the conqueror(s) often kill any existing young cubs, perhaps because females do not become fertile and receptive until their cubs mature or die.
+ </ph>
+ <ph id="226">
+ All in all, as many as 80 percent of the cubs will die before the age of two.
+ </ph>
+ </p>
+ <p id="56">
+ <ph id="227">
+ When first introduced to the rest of the pride, the cubs initially lack confidence when confronted with adult lions other than their mother.
+ </ph>
+ <ph id="228">
+ However, they soon begin to immerse themselves in the pride life, playing amongst themselves or attempting to initiate play with the adults.
+ </ph>
+ <ph id="229">
+ Lionesses with cubs of their own are more likely to be tolerant of another lioness's cubs than lionesses without cubs.
+ </ph>
+ <ph id="230">
+ The tolerance of the male lions towards the cubs varies—sometimes, a male will patiently let the cubs play with his tail or his mane, whereas another may snarl and bat the cubs away.
+ </ph>
+ <ph id="231">
+ </ph>
+ </p>
+ <p id="57">
+ <ph id="232">
+ Weaning occurs after six to seven months.
+ </ph>
+ <ph id="233">
+ Male lions reach maturity at about 3 years of age and, at 4–5 years of age, are capable of challenging and displacing the adult male(s) associated with another pride.
+ </ph>
+ <ph id="234">
+ They begin to age and weaken between 10 and 15 years of age at the latest, if they have not already been critically injured whilst defending the pride (once ousted from a pride by rival males, male lions rarely manage a second take-over).
+ </ph>
+ <ph id="235">
+ This leaves a short window for their own offspring to be born and mature.
+ </ph>
+ <ph id="236">
+ If they are able to procreate as soon as they take over a pride, potentially, they may have more offspring reaching maturity before they also are displaced.
+ </ph>
+ <ph id="237">
+ A lioness often will attempt to defend her cubs fiercely from a usurping male, but such actions are rarely successful.
+ </ph>
+ <ph id="238">
+ He usually kills all of the existing cubs who are less than two years old.
+ </ph>
+ <ph id="239">
+ A lioness is weaker and much lighter than a male; success is more likely when a group of three or four mothers within a pride join forces against one male.
+ </ph>
+ </p>
+ <p id="58">
+ <ph id="240">
+ Contrary to popuar belief, it is not only males that are ousted from their pride to become nomads, although the majority of females certainly do remain with their birth pride.
+ </ph>
+ <ph id="241">
+ However, when the pride becomes too large, the next generation of female cubs may be forced to leave to eke out their own territory.
+ </ph>
+ <ph id="242">
+ Furthermore, when a new male lion takes over the pride, subadult lions, both male and female, may be evicted.
+ </ph>
+ <ph id="243">
+ Life is harsh for a female nomad.
+ </ph>
+ <ph id="244">
+ Nomadic lionesses rarely manage to raise their cubs to maturity, without the protection of other pride members.
+ </ph>
+ </p>
+ <p id="59">
+ <ph id="245">
+ One scientific study reports that both males and females may interact homosexually.
+ </ph>
+ <ph id="246">
+ Male lions pair-bond for a number of days and initiate homosexual activity with affectionate nuzzling and caressing, leading to mounting and thrusting.
+ </ph>
+ <ph id="247">
+ A study found that about 8 percent of mountings have been observed to occur with other males.
+ </ph>
+ <ph id="248">
+ Female pairings are held to be fairly common in captivity, but have not been observed in the wild.
+ </ph>
+ </p>
+ <p id="60">
+ <ph id="249">
+ </ph>
+ </p>
+ </section>
+ <section id="12">
+ <title>
+ Health
+ </title>
+ <p id="61">
+ <ph id="250">
+ Though adult lions have no natural predators, evidence suggests that the majority die violently from humans or other lions.
+ </ph>
+ <ph id="251">
+ This is particularly true of male lions, who, as the main defenders of the pride, are more likely to come into aggressive contact with rival males.
+ </ph>
+ <ph id="252">
+ In fact, even though a male lion may reach an age of 15 or 16 years if he manages to avoid being ousted by other males, the majority of adult males do not live to be more than 10 years old.
+ </ph>
+ <ph id="253">
+ This is why the average lifespan of a male lion tends to be significantly less than that of a lioness in the wild.
+ </ph>
+ <ph id="254">
+ However, members of both sexes can be injured or even killed by other lions when two prides with overlapping territories come into conflict.
+ </ph>
+ </p>
+ <p id="62">
+ <ph id="255">
+ Various species of tick commonly infest the ears, neck and groin regions of most lions.
+ </ph>
+ <ph id="256">
+ Adult forms of several species of the tapeworm genus Taenia have been isolated from intestines, the lions having ingested larval forms from antelope meat.
+ </ph>
+ <ph id="257">
+ Lions in the Ngorongoro Crater were afflicted by an outbreak of stable fly (Stomoxys calcitrans) in 1962; this resulted in lions becoming covered in bloody bare patches and emaciated.
+ </ph>
+ <ph id="258">
+ Lions sought unsuccessfully to evade the biting flies by climbing trees or crawling into hyena burrows; many perished or emigrated as the population dropped from 70 to 15 individuals.
+ </ph>
+ <ph id="259">
+ A more recent outbreak in 2001 killed six lions.
+ </ph>
+ <ph id="260">
+ Lions, especially in captivity, are vulnerable to the Canine distemper virus (CDV), feline immunodeficiency virus (FIV), and feline infectious peritonitis (FIP).
+ </ph>
+ <ph id="261">
+ CDV is spread through domestic dogs and other carnivores; a 1994 outbreak in Serengeti National Park resulted in many lions developing neurological symptoms such as seizures.
+ </ph>
+ <ph id="262">
+ During the outbreak, several lions died from pneumonia and encephalitis.
+ </ph>
+ <ph id="263">
+ FIV, which is similar to HIV while not known to adversely affect lions, is worrisome enough in its effect in domestic cats that the Species Survival Plan recommends systematic testing in captive lions.
+ </ph>
+ <ph id="264">
+ It occurs with high to endemic frequency in several wild lion populations, but is mostly absent from Asiatic and Namibian lions.
+ </ph>
+ </p>
+ <p id="63">
+ <ph id="265">
+ </ph>
+ </p>
+ </section>
+ <section id="13">
+ <title>
+ Communication
+ </title>
+ <p id="64">
+ <ph id="266">
+ When resting, lion socialization occurs through a number of behaviors, and the animal's expressive movements are highly developed.
+ </ph>
+ <ph id="267">
+ The most common peaceful tactile gestures are head rubbing and social licking, which have been compared with grooming in primates.
+ </ph>
+ <ph id="268">
+ Head rubbing—nuzzling one's forehead, face and neck against another lion—appears to be a form of greeting, as it is seen often after an animal has been apart from others, or after a fight or confrontation.
+ </ph>
+ <ph id="269">
+ Males tend to rub other males, while cubs and females rub females.
+ </ph>
+ <ph id="270">
+ Social licking often occurs in tandem with head rubbing; it is generally mutual and the recipient appears to express pleasure.
+ </ph>
+ <ph id="271">
+ The head and neck are the most common parts of the body licked, which may have arisen out of utility, as a lion cannot lick these areas individually.
+ </ph>
+ </p>
+ <p id="65">
+ <ph id="272">
+ Lions have an array of facial expressions and body postures that serve as visual gestures.
+ </ph>
+ <ph id="273">
+ Their repertoire of vocalizations is also large; variations in intensity and pitch, rather than discrete signals, appear central to communication.
+ </ph>
+ <ph id="274">
+ Lion sounds include snarling, purring, hissing, coughing, miaowing, woofing and roaring.
+ </ph>
+ <ph id="275">
+ Lions tend to roar in a very characteristic manner, starting with a few deep, long roars that trail off into a series of shorter ones.
+ </ph>
+ <ph id="276">
+ They most often roar at night; the sound, which can be heard from a distance of 8&amp;#160;kilometres (5.0&amp;#160;mi), is used to advertise the animal's presence.
+ </ph>
+ <ph id="277">
+ Lions have the loudest roar of any big cat.
+ </ph>
+ </p>
+ <p id="66">
+ <ph id="278">
+ </ph>
+ </p>
+ </section>
+ <section id="14">
+ <title>
+ Interspecific predatory relationships
+ </title>
+ <p id="67">
+ <ph id="279">
+ The relationship between lions and spotted hyenas in areas where they coexist is unique in its complexity and intensity.
+ </ph>
+ <ph id="280">
+ Lions and spotted hyenas are both apex predators which feed on the same prey, and are therefore in direct competition with one another.
+ </ph>
+ <ph id="281">
+ As such, they will often fight over and steal each others' kills.
+ </ph>
+ <ph id="282">
+ Though hyenas are popularly assumed to be opportunistic scavengers profiting from the lion's hunting abilities, it is quite often the case that the reverse is true.
+ </ph>
+ <ph id="283">
+ In Tanzania's Ngorongoro Crater, the spotted hyena population greatly exceeds that of the resident lions, which obtain a large proportion of their food by stealing hyena prey.
+ </ph>
+ <ph id="284">
+ The feud between the two species however encompasses more than just battles over food.
+ </ph>
+ <ph id="285">
+ In animals, it is usually the case that territorial boundaries of another species are disregarded.
+ </ph>
+ <ph id="286">
+ Hyenas and lions are an exception to this; they set boundaries against each other as they would against members of their own species.
+ </ph>
+ <ph id="287">
+ Male lions in particular are extremely aggressive toward hyenas, and have been observed to hunt and kill hyenas without eating them.
+ </ph>
+ <ph id="288">
+ Conversely, hyenas are major predators of lion cubs, and will harass lionesses over kills.
+ </ph>
+ <ph id="289">
+ However, healthy adult males, even single ones, are generally avoided at all costs.
+ </ph>
+ </p>
+ <p id="68">
+ <ph id="290">
+ Lions tend to dominate smaller felines such as cheetahs and leopards in areas where they are sympatric.
+ </ph>
+ <ph id="291">
+ They will steal their kills and will kill their cubs and even adults when given the chance.
+ </ph>
+ <ph id="292">
+ The cheetah has a 50 percent chance of losing its kill to lions or other predators.
+ </ph>
+ <ph id="293">
+ Lions are major killers of cheetah cubs, up to 90 percent of which are lost in their first weeks of life due to attacks by other predators.
+ </ph>
+ <ph id="294">
+ Cheetahs avoid competition by hunting at different times of the day and hide their cubs in thick brush.
+ </ph>
+ <ph id="295">
+ Leopards also use such tactics, but have the advantage of being able to subsist much better on small prey than either lions or cheetahs.
+ </ph>
+ <ph id="296">
+ Also, unlike cheetahs, leopards can climb trees and use them to keep their cubs and kills away from lions.
+ </ph>
+ <ph id="297">
+ However, lionesses will occasionally be successful in climbing to retrieve leopard kills.
+ </ph>
+ <ph id="298">
+ Similarly, lions dominate African wild dogs, not only taking their kills but also preying on both young and adult dogs (although the latter are rarely caught).
+ </ph>
+ </p>
+ <p id="69">
+ <ph id="299">
+ The Nile crocodile is the only competing predator besides spotted hyenas and humans that can threaten the lion.
+ </ph>
+ <ph id="300">
+ Depending on the size of the crocodile and the lion, either can lose kills or carrion to the other.
+ </ph>
+ <ph id="301">
+ Lions have been known to kill crocodiles venturing onto land, while the reverse is true for lions entering waterways containing crocodiles, as evidenced by the fact that lion claws have on occasion been found in crocodile stomachs.
+ </ph>
+ </p>
+ <p id="70">
+ <ph id="302">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="6">
+ <title>
+ Distribution and habitat
+ </title>
+ <refbody>
+ <p id="71">
+ <ph id="303">
+ In Africa, lions can be found in savanna grasslands with scattered Acacia trees which serve as shade; their habitat in India is a mixture of dry savanna forest and very dry deciduous scrub forest.
+ </ph>
+ <ph id="304">
+ In relatively recent times the habitat of lions spanned the southern parts of Eurasia, ranging from Greece to India, and most of Africa except the central rainforest-zone and the Sahara desert.
+ </ph>
+ <ph id="305">
+ Herodotus reported that lions had been common in Greece around 480 BC; they attacked the baggage camels of the Persian king Xerxes on his march through the country.
+ </ph>
+ <ph id="306">
+ Aristotle considered them rare by 300 BC and by 100 AD extirpated.
+ </ph>
+ <ph id="307">
+ A population of the Asiatic Lion survived until the tenth century in the Caucasus, their last European outpost.
+ </ph>
+ </p>
+ <p id="72">
+ <ph id="308">
+ The species was eradicated from Palestine by the Middle Ages and from most of the rest of Asia after the arrival of readily available firearms in the eighteenth century.
+ </ph>
+ <ph id="309">
+ Between the late nineteenth and early twentieth century they became extinct in North Africa and the Middle East.
+ </ph>
+ <ph id="310">
+ By the late nineteenth century the lion had disappeared from Turkey and most of northern India, while the last sighting of a live Asiatic lion in Iran was in 1941 (between Shiraz and Jahrom, Fars province), though the corpse of a lioness was found on the banks of Karun river, Khūzestān Province in 1944.
+ </ph>
+ <ph id="311">
+ There are no subsequent reliable reports from Iran.
+ </ph>
+ <ph id="312">
+ The subspecies now survives only in and around the Gir Forest of northwestern India.
+ </ph>
+ <ph id="313">
+ About 300 lions live in a 1,412 km² (558 square miles) sanctuary in the state of Gujarat, which covers most of the forest.
+ </ph>
+ <ph id="314">
+ Their numbers are slowly increasing.
+ </ph>
+ </p>
+ <p id="73">
+ <ph id="315">
+ Until the late Pleistocene (about 10,000 years ago), the lion was the most widespread land mammal aside from man.
+ </ph>
+ <ph id="316">
+ They were found in most of Africa, much of Eurasia from western Europe to India and the Bering land bridge, and in the Americas from Yukon to Peru.
+ </ph>
+ <ph id="317">
+ Parts of this range were occupied by subspecies that are extinct today.
+ </ph>
+ </p>
+ <p id="74">
+ <ph id="318">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="7">
+ <title>
+ Population and conservation status
+ </title>
+ <refbody>
+ <p id="75">
+ <ph id="319">
+ Most lions now live in eastern and southern Africa, and their numbers there are rapidly decreasing, with an estimated 30–50 percent decline over the last two decades.
+ </ph>
+ <ph id="320">
+ Currently, estimates of the African lion population range between 16,500 and 47,000 living in the wild in 2002–2004, down from early 1990s estimates that ranged as high as 100,000 and perhaps 400,000 in 1950.
+ </ph>
+ <ph id="321">
+ The cause of the decline is not well-understood, and may not be reversible.
+ </ph>
+ <ph id="322">
+ Currently, habitat loss and conflicts with humans are considered the most significant threats to the species.
+ </ph>
+ <ph id="323">
+ The remaining populations are often geographically isolated from each other, which can lead to inbreeding, and consequently, a lack of genetic diversity.
+ </ph>
+ <ph id="324">
+ Therefore the lion is considered a vulnerable species by the International Union for Conservation of Nature and Natural Resources, while the Asiatic subspecies is critically endangered.
+ </ph>
+ <ph id="325">
+ The lion population in the region of West Africa is isolated from lion populations of Central Africa, with little or no exchange of breeding individuals.
+ </ph>
+ <ph id="326">
+ The number of mature individuals in West Africa is estimated by two separate recent surveys at 850–1,160 (2002/2004).
+ </ph>
+ <ph id="327">
+ There is disagreement over the size of the largest individual population in West Africa: the estimates range from 100 to 400 lions in Burkina Faso's Arly-Singou ecosystem.
+ </ph>
+ </p>
+ <p id="76">
+ <ph id="328">
+ Conservation of both African and Asian lions has required the setup and maintenance of national parks and game reserves; among the best known are Etosha National Park in Namibia, Serengeti National Park in Tanzania, and Kruger National Park in eastern South Africa.
+ </ph>
+ <ph id="329">
+ Outside these areas, the issues arising from lions' interaction with livestock and people usually results in the elimination of the former.
+ </ph>
+ <ph id="330">
+ In India, the last refuge of the Asiatic lion is the 1,412&amp;#160;km² (558&amp;#160;square miles) Gir Forest National Park in western India which had about 359&amp;#160;lions (as of April 2006).
+ </ph>
+ <ph id="331">
+ As in Africa, numerous human habitations are close by with the resultant problems between lions, livestock, locals and wildlife officials.
+ </ph>
+ <ph id="332">
+ The Asiatic Lion Reintroduction Project plans to establish a second independent population of Asiatic Lions at the Kuno Wildlife Sanctuary in the Indian state of Madhya Pradesh.
+ </ph>
+ <ph id="333">
+ It is important to start a second population to serve as a gene pool for the last surviving Asiatic lions and to help develop and maintain genetic diversity enabling the species to survive.
+ </ph>
+ </p>
+ <p id="77">
+ <ph id="334">
+ The former popularity of the Barbary lion as a zoo animal has meant that scattered lions in captivity are likely to be descended from Barbary Lion stock.
+ </ph>
+ <ph id="335">
+ This includes twelve lions at Port Lympne Wild Animal Park in Kent, England that are descended from animals owned by the King of Morocco.
+ </ph>
+ <ph id="336">
+ Another eleven animals believed to be Barbary lions were found in Addis Ababa zoo, descendants of animals owned by Emperor Haile Selassie.
+ </ph>
+ <ph id="337">
+ WildLink International, in collaboration with Oxford University, launched their ambitious International Barbary Lion Project with the aim of identifying and breeding Barbary lions in captivity for eventual reintroduction into a national park in the Atlas Mountains of Morocco.
+ </ph>
+ </p>
+ <p id="78">
+ <ph id="338">
+ Following the discovery of the decline of lion population in Africa, several coordinated efforts involving lion conservation have been organised in an attempt to stem this decline.
+ </ph>
+ <ph id="339">
+ Lions are one species included in the Species Survival Plan, a coordinated attempt by the Association of Zoos and Aquariums to increase its chances of survival.
+ </ph>
+ <ph id="340">
+ The plan was originally started in 1982 for the Asiatic lion, but was suspended when it was found that most Asiatic lions in North American zoos were not genetically pure, having been hybridized with African lions.
+ </ph>
+ <ph id="341">
+ The African lion plan started in 1993, focusing especially on the South African subspecies, although there are difficulties in assessing the genetic diversity of captive lions, since most individuals are of unknown origin, making maintenance of genetic diversity a problem.
+ </ph>
+ </p>
+ <p id="79">
+ <ph id="342">
+ </ph>
+ </p>
+ <section id="15">
+ <title>
+ Man-eaters
+ </title>
+ <p id="80">
+ <ph id="343">
+ While lions do not usually hunt people, some (usually males) seem to seek out human prey; well-publicized cases include the Tsavo maneaters, where 28 railway workers building the Kenya-Uganda Railway were taken by lions over nine months during the construction of a bridge over the Tsavo River in Kenya in 1898, and the 1991 Mfuwe man-eater, which killed six people in the Laungwa River Valley in Zambia.
+ </ph>
+ <ph id="344">
+ In both, the hunters who killed the lions wrote books detailing the animals' predatory behavior.
+ </ph>
+ <ph id="345">
+ The Mfuwe and Tsavo incidents bear similarities: the lions in both incidents were larger than normal, lacked manes, and seemed to suffer from tooth decay.
+ </ph>
+ <ph id="346">
+ The infirmity theory, including tooth decay, is not favored by all researchers.
+ </ph>
+ <ph id="347">
+ An analysis of teeth and jaws of man-eating lions in museum collections suggests that, while tooth decay may explain some incidents, prey depletion in human-dominated areas is a more likely cause of lion predation on humans.
+ </ph>
+ <ph id="348">
+ In their analysis of Tsavo and man-eating generally, Kerbis Peterhans and Gnoske acknowledge that sick or injured animals may be more prone to man-eating, but that the behavior is "not unusual, nor necessarily 'aberrant'"
+ </ph>
+ <ph id="349">
+ where the opportunity exists; if inducements such as access to livestock or human corpses are present, lions will regularly prey upon human beings.
+ </ph>
+ <ph id="350">
+ The authors note that the relationship is well-attested amongst other pantherines and primates in the paleontological record.
+ </ph>
+ </p>
+ <p id="81">
+ <ph id="351">
+ The lion's proclivity for man-eating has been systematically examined.
+ </ph>
+ <ph id="352">
+ American and Tanzanian scientists report that man-eating behavior in rural areas of Tanzania increased greatly from 1990 to 2005.
+ </ph>
+ <ph id="353">
+ At least 563 villagers were attacked and many eaten over this period—a number far exceeding the more famed "Tsavo"
+ </ph>
+ <ph id="354">
+ incidents of a century earlier.
+ </ph>
+ <ph id="355">
+ The incidents occurred near Selous National Park in Rufiji District and in Lindi Province near the Mozambican border.
+ </ph>
+ <ph id="356">
+ While the expansion of villagers into bush country is one concern, the authors argue that conservation policy must mitigate the danger because, in this case, conservation contributes directly to human deaths.
+ </ph>
+ <ph id="357">
+ Cases in Lindi have been documented where lions seize humans from the center of substantial villages.
+ </ph>
+ </p>
+ <p id="82">
+ <ph id="358">
+ Author Robert R.
+ </ph>
+ <ph id="359">
+ Frump wrote in The Man-eaters of Eden that Mozambican refugees regularly crossing Kruger National Park at night in South Africa are attacked and eaten by the lions; park officials have conceded that man-eating is a problem there.
+ </ph>
+ <ph id="360">
+ Frump believes thousands may have been killed in the decades after apartheid sealed the park and forced the refugees to cross the park at night.
+ </ph>
+ <ph id="361">
+ For nearly a century before the border was sealed, Mozambicans had regularly walked across the park in daytime with little harm.
+ </ph>
+ </p>
+ <p id="83">
+ <ph id="362">
+ Packer estimates more than 200 Tanzanians are killed each year by lions, crocodiles, elephants, hippos, and snakes, and that the numbers could be double that amount, with lions thought to kill at least 70 of those.
+ </ph>
+ <ph id="363">
+ Packer and Ikanda are among the few conservationists who believe western conservation efforts must take account of these matters not just because of ethical concerns about human life, but also for the long term success of conservation efforts and lion preservation.
+ </ph>
+ </p>
+ <p id="84">
+ <ph id="364">
+ A man-eating lion was killed by game scouts in Southern Tanzania in April 2004.
+ </ph>
+ <ph id="365">
+ It is believed to have killed and eaten at least 35&amp;#160;people in a series of incidents covering several villages in the Rufiji Delta coastal region.
+ </ph>
+ <ph id="366">
+ Dr Rolf D.
+ </ph>
+ <ph id="367">
+ Baldus, the GTZ wildlife programme coordinator, commented that it was likely that the lion preyed on humans because it had a large abscess underneath a molar which was cracked in several places.
+ </ph>
+ <ph id="368">
+ He further commented that "This lion probably experienced a lot of pain, particularly when it was chewing."
+ </ph>
+ <ph id="369">
+ GTZ is the German development cooperation agency and has been working with the Tanzanian government on wildlife conservation for nearly two decades.
+ </ph>
+ <ph id="370">
+ As in other cases this lion was large, lacked a mane, and had a tooth problem.
+ </ph>
+ </p>
+ <p id="85">
+ <ph id="371">
+ The "All-Africa"
+ </ph>
+ <ph id="372">
+ record of man-eating generally is considered to be not Tsavo, but the lesser-known incidents in the late 1930s through the late 1940s in what was then Tanganyika (now Tanzania).
+ </ph>
+ <ph id="373">
+ George Rushby, game warden and professional hunter, eventually dispatched the pride, which over three generations is thought to have killed and eaten 1,500 to 2,000 in what is now Njombe district.
+ </ph>
+ </p>
+ <p id="86">
+ <ph id="374">
+ </ph>
+ </p>
+ </section>
+ <section id="16">
+ <title>
+ In captivity
+ </title>
+ <p id="87">
+ <ph id="375">
+ Widely seen in captivity, lions are part of a group of exotic animals that are the core of zoo exhibits since the late eighteenth century; members of this group are invariably large vertebrates and include elephants, rhinoceroses, hippopotamuses, large primates, and other big cats; zoos sought to gather as many of these species as possible.
+ </ph>
+ <ph id="376">
+ Though many modern zoos are more selective about their exhibits, there are over 1000 African and 100 Asiatic lions in zoos and wildlife parks around the world.
+ </ph>
+ <ph id="377">
+ They are considered an ambassador species and are kept for tourism, education and conservation purposes.
+ </ph>
+ <ph id="378">
+ Lions can reach an age of over 20 years in captivity; Apollo, a resident lion of Honolulu Zoo in Honolulu, Hawaii, died at age 22 in August 2007.
+ </ph>
+ <ph id="379">
+ His two sisters, born in 1986, are still living.
+ </ph>
+ <ph id="380">
+ A zoo-based lion breeding programme usually takes into account the separation of the various lion subspecies, while mitigating the inbreeding that is likely to occur when animals are divided by subspecies.
+ </ph>
+ </p>
+ <p id="88">
+ <ph id="381">
+ Lions were kept and bred by Assyrian kings as early as 850 BC, and Alexander the Great was said to have been presented with tame lions by the Malhi of northern India.
+ </ph>
+ <ph id="382">
+ Later in Roman times, lions were kept by emperors to take part in the gladiator arenas.
+ </ph>
+ <ph id="383">
+ Roman notables, including Sulla, Pompey, and Julius Caesar, often ordered the mass slaughter of hundreds of lions at a time.
+ </ph>
+ <ph id="384">
+ In the East, lions were tamed by Indian princes, and Marco Polo reported that Kublai Khan kept lions inside.
+ </ph>
+ <ph id="385">
+ The first European "zoos"
+ </ph>
+ <ph id="386">
+ spread amongst noble and royal families in the thirteenth century, and until the seventeenth century were called seraglios; at that time, they came to be called menageries, an extension of the cabinet of curiosities.
+ </ph>
+ <ph id="387">
+ They spread from France and Italy during the Renaissance to the rest of Europe.
+ </ph>
+ <ph id="388">
+ In England, although the seraglio tradition was less developed, Lions were kept at the Tower of London in a seraglio established by King John in the thirteenth century, probably stocked with animals from an earlier menagerie started in 1125 by Henry I at his palace in Woodstock, near Oxford; where lions had been reported stocked by William of Malmesbury.
+ </ph>
+ </p>
+ <p id="89">
+ <ph id="389">
+ Seraglios served as expressions of the nobility's power and wealth.
+ </ph>
+ <ph id="390">
+ Animals such as big cats and elephants, in particular, symbolized power, and would be pitted in fights against each other or domesticated animals.
+ </ph>
+ <ph id="391">
+ By extension, menageries and seraglios served as demonstrations of the dominance of man over nature.
+ </ph>
+ <ph id="392">
+ Consequently, the defeat of such natural "lords"
+ </ph>
+ <ph id="393">
+ by a cow in 1682 astonished the spectators, and the flight of an elephant before a rhinoceros drew jeers.
+ </ph>
+ <ph id="394">
+ Such fights would slowly fade out in the seventeenth century with the spread of the menagerie and their appropriation by the commoners.
+ </ph>
+ <ph id="395">
+ The tradition of keeping big cats as pets would last into the nineteenth century, at which time it was seen as highly eccentric.
+ </ph>
+ </p>
+ <p id="90">
+ <ph id="396">
+ The presence of lions at the Tower of London was intermittent, being restocked when a monarch or his consort, such as Margaret of Anjou the wife of Henry VI, either sought or were given animals.
+ </ph>
+ <ph id="397">
+ Records indicate they were kept in poor conditions there in the seventeenth century, in contrast to more open conditions in Florence at the time.
+ </ph>
+ <ph id="398">
+ The menagerie was open to the public by the eighteenth century; admission was a sum of three half-pence or the supply of a cat or dog for feeding to the lions.
+ </ph>
+ <ph id="399">
+ A rival menagerie at the Exeter Exchange also exhibited lions until the early nineteenth century.
+ </ph>
+ <ph id="400">
+ The Tower menagerie was closed down by William IV, and animals transferred to the London Zoo which opened its gates to the public on 27 April 1828.
+ </ph>
+ </p>
+ <table>
+ <tr>
+ <td align="center">
+ Animal species disappear when they cannot peacefully orbit the center of gravity that is man.
+Pierre-Amédée Pichot, 1891
+ </td>
+ </tr>
+ </table>
+ <p id="91">
+ <ph id="401">
+ The wild animals trade flourished alongside improved colonial trade of the nineteenth century.
+ </ph>
+ <ph id="402">
+ Lions were considered fairly common and inexpensive.
+ </ph>
+ <ph id="403">
+ Although they would barter higher than tigers, they were less costly than larger, or more difficult to transport animals such as the giraffe and hippopotamus, and much less than pandas.
+ </ph>
+ <ph id="404">
+ Like other animals, lions were seen as little more than a natural, boundless commodity that was mercilessly exploited with terrible losses in capture and transportation.
+ </ph>
+ <ph id="405">
+ The widely reproduced imagery of the heroic hunter chasing lions would dominate a large part of the century.
+ </ph>
+ <ph id="406">
+ Explorers and hunters exploited a popular Manichean division of animals into "good"
+ </ph>
+ <ph id="407">
+ and "evil"
+ </ph>
+ <ph id="408">
+ to add thrilling value to their adventures, casting themselves as heroic figures.
+ </ph>
+ <ph id="409">
+ This resulted in big cats, always suspected of being man-eaters, representing "both the fear of nature and the satisfaction of having overcome it."
+ </ph>
+ </p>
+ <p id="92">
+ <ph id="410">
+ Lions were kept in cramped and squalid conditions at London Zoo until a larger lion house with roomier cages was built in the 1870s.
+ </ph>
+ <ph id="411">
+ Further changes took place in the early twentieth century, when Carl Hagenbeck designed enclosures more closely resembling a natural habitat, with concrete 'rocks', more open space and a moat instead of bars.
+ </ph>
+ <ph id="412">
+ He designed lion enclosures for both Melbourne Zoo and Sydney's Taronga Zoo, among others, in the early twentieth century.
+ </ph>
+ <ph id="413">
+ Though his designs were popular, the old bars and cage enclosures prevailed until the 1960s in many zoos.
+ </ph>
+ <ph id="414">
+ In the later decades of the twentieth century, larger, more natural enclosures and the use of wire mesh or laminated glass instead of lowered dens allowed visitors to come closer than ever to the animals, with some attractions even placing the den on ground higher than visitors, such as the Cat Forest/Lion Overlook of Oklahoma City Zoological Park.
+ </ph>
+ <ph id="415">
+ Lions are now housed in much larger naturalistic areas; modern recommended guidelines more closely approximate conditions in the wild with closer attention to the lions' needs, highlighting the need for dens in separate areas, elevated positions in both sun and shade where lions can sit and adequate ground cover and drainage as well as sufficient space to roam.
+ </ph>
+ </p>
+ <p id="93">
+ <ph id="416">
+ There have also been instances where a lion was kept by a private individual, such as the lioness Elsa, who was raised by George Adamson and his wife Joy Adamson and came to develop a strong bonds with them, particularly the latter.
+ </ph>
+ <ph id="417">
+ The lioness later achieved fame, her life being documented in a series of books and films.
+ </ph>
+ </p>
+ <p id="94">
+ <ph id="418">
+ </ph>
+ </p>
+ </section>
+ <section id="17">
+ <title>
+ Baiting and taming
+ </title>
+ <p id="95">
+ <ph id="419">
+ Lion-baiting is a blood sport involving the baiting of lions in combat with other animals, usually dogs.
+ </ph>
+ <ph id="420">
+ Records of it exist in ancient times through until the seventeenth century.
+ </ph>
+ <ph id="421">
+ It was finally banned in Vienna by 1800 and England in 1825.
+ </ph>
+ </p>
+ <p id="96">
+ <ph id="422">
+ Lion taming refers to the practice of taming lions for entertainment, either as part of an established circus or as an individual act, such as Siegfried &amp;amp; Roy.
+ </ph>
+ <ph id="423">
+ The term is also often used for the taming and display of other big cats such as tigers, leopards, and cougars.
+ </ph>
+ <ph id="424">
+ The practice was pioneered in the first half of the nineteenth century by Frenchman Henri Martin and American Isaac Van Amburgh who both toured widely, and whose techniques were copied by a number of followers.
+ </ph>
+ <ph id="425">
+ Van Amburgh performed before Queen Victoria of the United Kingdom in 1838 when he toured Great Britain.
+ </ph>
+ <ph id="426">
+ Martin composed a pantomime titled Les Lions de Mysore ("the lions of Mysore"), an idea that Amburgh quickly borrowed.
+ </ph>
+ <ph id="427">
+ These acts eclipsed equestrianism acts as the central display of circus shows, but truly entered public consciousness in the early twentieth century with cinema.
+ </ph>
+ <ph id="428">
+ In demonstrating the superiority of man over animal, lion taming served a purpose similar to animal fights of previous centuries.
+ </ph>
+ <ph id="429">
+ The now iconic lion tamer's chair was possibly first used by American Clyde Beatty (1903–1965).
+ </ph>
+ </p>
+ <p id="97">
+ <ph id="430">
+ </ph>
+ </p>
+ </section>
+ <section id="18">
+ <title>
+ Cultural depictions
+ </title>
+ <p id="98">
+ <ph id="431">
+ The lion has been an icon for humanity for thousands of years, appearing in cultures across Europe, Asia, and Africa.
+ </ph>
+ <ph id="432">
+ Despite incidents of attacks on humans, lions have enjoyed a positive depiction in culture as strong but noble.
+ </ph>
+ <ph id="433">
+ A common depiction is their representation as "king of the jungle"
+ </ph>
+ <ph id="434">
+ or "king of the beasts"; hence, the lion has been a popular symbol of royalty and stateliness, as well as a symbol of bravery; it is featured in several fables of the sixth century BC Greek storyteller Aesop.
+ </ph>
+ </p>
+ <p id="99">
+ <ph id="435">
+ Representations of lions date back 32,000&amp;#160;years; the lion-headed ivory carving from Vogelherd cave in the Swabian Alb in southwestern Germany has been determined to be about 32,000&amp;#160;years old from the Aurignacian culture.
+ </ph>
+ <ph id="436">
+ Two lions were depicted mating in the Chamber of Felines in 15,000-year-old Paleolithic cave paintings in the Lascaux caves.
+ </ph>
+ <ph id="437">
+ Cave lions are also depicted in the Chauvet Cave, discovered in 1994; this has been dated at 32,000&amp;#160;years of age, though it may be of similar or younger age to Lascaux.
+ </ph>
+ </p>
+ <p id="100">
+ <ph id="438">
+ Ancient Egypt venerated the lioness (the fierce hunter) as their war deities and among those in the Egyptian pantheon are, Bast, Mafdet, Menhit, Pakhet, Sekhmet, Tefnut, and the Sphinx; Among the Egyptian pantheon also are sons of these goddesses such as, Maahes, and, as attested by Egyptians as a Nubian deity, Dedun.
+ </ph>
+ </p>
+ <p id="101">
+ <ph id="439">
+ Careful examination of the lion deities noted in many ancient cultures reveal that many are lioness also.
+ </ph>
+ <ph id="440">
+ Admiration for the co-operative hunting strategies of lionesses was evident in very ancient times.
+ </ph>
+ <ph id="441">
+ Most of the lion gates depict lionesses.
+ </ph>
+ <ph id="442">
+ The Nemean lion was symbolic in Ancient Greece and Rome, represented as the constellation and zodiac sign Leo, and described in mythology, where its skin was borne by the hero Heracles.
+ </ph>
+ </p>
+ <p id="102">
+ <ph id="443">
+ The lion is the biblical emblem of the tribe of Judah and later the Kingdom of Judah.
+ </ph>
+ <ph id="444">
+ It is contained within Jacob's blessing to his fourth son in the penultimate chapter of the Book of Genesis, "Judah is a lion's whelp; On prey, my son have you grown.
+ </ph>
+ <ph id="445">
+ He crouches, lies down like a lion, like the king of beasts—who dare rouse him?"
+ </ph>
+ <ph id="446">
+ (Genesis 49:9).
+ </ph>
+ <ph id="447">
+ In the modern state of Israel, the lion remains the symbol of the capital city of Jerusalem, emblazoned on both the flag and coat of arms of the city.
+ </ph>
+ </p>
+ <p id="103">
+ <ph id="448">
+ The lion was a prominent symbol in both the Old Babylonian and Neo-Babylonian Empire periods.
+ </ph>
+ <ph id="449">
+ The classic Babylonian lion motif, found as a statue, carved or painted on walls, is often referred to as the striding lion of Babylon.
+ </ph>
+ <ph id="450">
+ It is in Babylon that the biblical Daniel is said to have been delivered from the lion's den.
+ </ph>
+ <ph id="451">
+ Such symbolism was appropriated by Saddam Hussein's regime in Iraq for their Lion of Babylon tank, with the technology adapted from a Russian model.
+ </ph>
+ <ph id="452">
+ Narasimha ("man-lion") is described as an incarnation (avatara) of Vishnu within the Puranic texts of Hinduism; who takes the form of half-man/half-lion, having a human torso and lower body, but with a lion-like face and claws.
+ </ph>
+ <ph id="453">
+ it is worshiped as "Lion God."
+ </ph>
+ </p>
+ <p id="104">
+ <ph id="454">
+ Singh is an ancient Indian vedic name meaning "lion"
+ </ph>
+ <ph id="455">
+ (Asiatic lion), dating back over 2000 years to ancient India.
+ </ph>
+ <ph id="456">
+ It was originally only used by Rajputs a Hindu Kshatriya or military caste in India.
+ </ph>
+ <ph id="457">
+ After the birth of the Khalsa brotherhood in 1699, the Sikhs also adopted the name "Singh"
+ </ph>
+ <ph id="458">
+ due to the wishes of Guru Gobind Singh.
+ </ph>
+ <ph id="459">
+ Along with millions of Hindu Rajputs today, it is also used by over 20 million Sikhs worldwide.
+ </ph>
+ </p>
+ <p id="105">
+ <ph id="460">
+ Found famously on numerous flags and coats of arms all across Asia and Europe, the Asiatic lions also stand firm on the National Emblem of India..
+ </ph>
+ </p>
+ <p id="106">
+ <ph id="461">
+ Farther south on the Indian subcontinent, the Asiatic lion is symbolic for the Sinhalese, Sri Lanka's ethnic majority; the term derived from the Indo-Aryan Sinhala, meaning the "lion people"
+ </ph>
+ <ph id="462">
+ or "people with lion blood", while a sword wielding lion is the central figure on the national flag of Sri Lanka.
+ </ph>
+ </p>
+ <p id="107">
+ <ph id="463">
+ The Asiatic lion is a common motif in Chinese art.
+ </ph>
+ <ph id="464">
+ They were first used in art during the late Spring and Autumn Period (fifth or sixth century BC), and became much more popular during the Han Dynasty (206 BC – AD 220), when imperial guardian lions started to be placed in front of imperial palaces for protection.
+ </ph>
+ <ph id="465">
+ Because lions have never been native to China, early depictions were somewhat unrealistic; after the introduction of Buddhist art to China in the Tang Dynasty (after the sixth century AD), lions were usually depicted without wings, their bodies became thicker and shorter, and their manes became curly.
+ </ph>
+ <ph id="466">
+ The lion dance is a form of traditional dance in Chinese culture in which performers mimic a lion's movements in a lion costume, often with musical accompaniment from cymbals, drums and gongs.
+ </ph>
+ <ph id="467">
+ They are performed at Chinese New Year, the August Moon Festival and other celebratory occasions for good luck.
+ </ph>
+ </p>
+ <p id="108">
+ <ph id="468">
+ The island nation of Singapore (Singapura) derives its name from the Malay words singa (lion) and pura (city), which in turn is from the Tamil-Sanskrit சிங்க singa सिंह siṃha and पुर புர pura, which is cognate to the Greek πόλις, pólis.
+ </ph>
+ <ph id="469">
+ According to the Malay Annals, this name was given by a fourteenth century Sumatran Malay prince named Sang Nila Utama, who, on alighting the island after a thunderstorm, spotted an auspicious beast on shore that his chief minister identified as a lion (Asiatic lion).
+ </ph>
+ <ph id="470">
+ Recent studies of Singapore indicate that lions have never lived there, and the beast seen by Sang Nila Utama was more likely to have been a tiger.
+ </ph>
+ </p>
+ <p id="109">
+ <ph id="471">
+ "Aslan"
+ </ph>
+ <ph id="472">
+ or "Arslan (Ottoman ارسلان arslān and اصلان aṣlān) is the Turkish and Mongolian word for "lion".
+ </ph>
+ <ph id="473">
+ It was used as a title by a number of Seljuk and Ottoman rulers, including Alp Arslan and Ali Pasha, and is a Turkic/Iranian name.
+ </ph>
+ </p>
+ <p id="110">
+ <ph id="474">
+ "Lion"
+ </ph>
+ <ph id="475">
+ was the nickname of medieval warrior rulers with a reputation for bravery, such as Richard I of England, known as Richard the Lionheart,, Henry the Lion (German: Heinrich der Löwe), Duke of Saxony and Robert III of Flanders nicknamed "The Lion of Flanders"—a major Flemish national icon up to the present.
+ </ph>
+ <ph id="476">
+ Lions are frequently depicted on coats of arms, either as a device on shields themselves, or as supporters.
+ </ph>
+ <ph id="477">
+ (The lioness is much more infrequent.) The formal language of heraldry, called blazon, employs French terms to describe the images precisely.
+ </ph>
+ <ph id="478">
+ Such descriptions specified whether lions or other creatures were "rampant"
+ </ph>
+ <ph id="479">
+ or "passant", that is whether they were rearing or crouching.
+ </ph>
+ <ph id="480">
+ The lion is used as a symbol of sporting teams, from national soccer teams such as England, Scotland and Singapore to famous clubs such as the Detroit Lions of the NFL, Chelsea and Aston Villa of the English Premier League, (and the Premiership itself) to a host of smaller clubs around the world.
+ </ph>
+ <ph id="481">
+ Villa sport a Scottish Lion Rampant on their crest, as do Rangers and Dundee United of the Scottish Premier League.
+ </ph>
+ </p>
+ <p id="111">
+ <ph id="482">
+ Lions continue to feature in modern literature, from the messianic Aslan in The Lion, the Witch and the Wardrobe and following books from the Narnia series written by C.
+ </ph>
+ <ph id="483">
+ S.
+ </ph>
+ <ph id="484">
+ Lewis, to the comedic Cowardly Lion in The Wonderful Wizard of Oz.
+ </ph>
+ <ph id="485">
+ The advent of moving pictures saw the continued presence of lion symbolism; one of the most iconic and widely recognised lions is Leo the Lion, the mascot for Metro-Goldwyn-Mayer (MGM) studios, which has been in use since the 1920s.
+ </ph>
+ <ph id="486">
+ The 1960s saw the appearance of what is possibly the most famous lioness, the Kenyan animal Elsa in the movie Born Free, based on the true-life international bestselling book of the same title.
+ </ph>
+ <ph id="487">
+ The lion's role as King of the Beasts has been used in cartoons, from the 1950s manga which gave rise to the first Japanese colour TV animation series, Kimba the White Lion, Leonardo Lion of King Leonardo and his Short Subjects, both from the 1960s, up to the 1994 Disney animated feature film The Lion King, which also featured the popular song "The Lion Sleeps Tonight"
+ </ph>
+ <ph id="488">
+ in its soundtrack.
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="imagelist">
+ <refbody>
+ <image href="#DEMOLIBRARY#/images/250px-Lion_in_masai_mara.jpg">
+ <alt>
+ Male
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Lion_in_Ngorongoro_Crater%2C_Tanzania.jpg">
+ <alt>
+ Female (Lioness)
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Status_iucn3.1_VU.svg.png">
+ <alt>
+ 180px-Status_iucn3.1_VU.svg.png
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Lion_distribution.svg.png">
+ <alt>
+ Distribution of lions in Africa
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Map_Guj_Nat_Parks_Sanctuary.png">
+ <alt>
+ Distribution of lions in India
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Panthera_leo_Kruger_Skull.jpg">
+ <alt>
+ Skull of a modern lion at Kruger National Park
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/140px-P_l_Bleyenberghi.jpg">
+ <alt>
+ Southwest African lion (Panthera leo bleyenberghi)
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/300px-Lascaux-diverticule-f%C3%A9lins.jpg">
+ <alt>
+ Cave Lions, Chamber of Felines, Lascaux caves
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Bertramliger.jpg">
+ <alt>
+ A liger is the offspring of a female tiger and male lion.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-HansomeLion_002.jpg">
+ <alt>
+ During confrontations with others, the mane makes the lion look bigger than he really is.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Lionesses%2C_Masai_Mara%2C_Kenya.jpg">
+ <alt>
+ Two lionesses in Masai Mara, Kenya
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Wiki_lion.jpg">
+ <alt>
+ Thermographic image of a lion, showing the insulating mane
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Maneless_lion_from_Tsavo_East_National_Park.png">
+ <alt>
+ A maneless male lion, who also has little body hair—from Tsavo East National Park, Kenya
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Lightmatter_lioness.jpg">
+ <alt>
+ Lioness showing the ruff that sometimes leads to misidentification as a male
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-White_Lion.jpg">
+ <alt>
+ White lions owe their coloring to a recessive gene; they are rare forms of the subspecies Panthera leo krugeri
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Pride_of_lions.JPG">
+ <alt>
+ A pride on the move near Governors Camp, in the Massai Mara, Kenya
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Serengeti_Lion_Running_saturated.jpg">
+ <alt>
+ Lioness in a burst of speed while hunting in the Serengeti
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Female_Lion.JPG">
+ <alt>
+ While a lioness such as this has very sharp teeth, prey is usually killed by strangulation
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/240px-7_lions.jpg">
+ <alt>
+ 7 lions along the road in the Masai Mara park reserve in Kenya
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/200px-Lions_and_a_Zebra_a.jpg">
+ <alt>
+ The hunters of a pride sharing a zebra where the kill occurred
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/140px-Lion_pair2.jpg">
+ <alt>
+ During a mating bout, a couple may copulate twenty to forty times a day for several days; the ruff of the female is clearly visible
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-PregnantLioness.jpg">
+ <alt>
+ A pregnant lioness (foreground)
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Male_Lion_and_Cub_Chitwa_South_Africa_Luca_Galuzzi_2004.JPG">
+ <alt>
+ The tolerance of male lions towards the cubs varies. They are, however, generally more likely to share food with the cubs than with the lionesses
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Lion_cub_with_mother.jpg">
+ <alt>
+ Head rubbing and licking are common social behaviors within a pride, this cub's mother gives it an affectionate nudge
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Map_Guj_Nat_Parks_Sanctuary.png">
+ <alt>
+ The Gir Forest in the State of Gujarat, India is the last natural range of the 300-odd wild Asiatic Lions. Plans are afoot to re-introduce some to Kuno Wildlife Sanctuary in the neighboring State of Madhya Pradesh in India.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Lion_cubs_Serengeti.jpg">
+ <alt>
+ Lion cubs playing in the Serengeti
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Asiatic.lioness.arp.jpg">
+ <alt>
+ An Asiatic Lioness Panthera leo persica, named Moti, was born in Helsinki Zoo (Finland) in October 1994; she arrived at Bristol Zoo (England) in January 1996. The Gir Forest in India is the natural home of the Asiatic lion but she was born in captivity.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Maneating_lion.jpg">
+ <alt>
+ A man-eating lion in British East Africa
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Lion_at_zoo.jpg">
+ <alt>
+ A Lion at Paignton Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Durer_lions_%28sketch%29.jpg">
+ <alt>
+ Albrecht Dürer, Lions sketch. Circa 1520.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Lion_-_melbourne_zoo.jpg">
+ <alt>
+ Lion at Melbourne Zoo enjoying an elevated grassy area with some tree shelter
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Circus_Lion_Tamer.jpg">
+ <alt>
+ Nineteenth century etching of a lion tamer in a cage of lions
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/140px-GD-EG-KomOmbo016.JPG">
+ <alt>
+ The warrior goddess Sekhmet, shown with her sun disk and cobra crown
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Mycenae_lion_gate_detail_dsc06384.jpg">
+ <alt>
+ The Lion Gate of Mycenae (detail)—two lionesses flank the central column that represents a goddess—c. 1300 BC renovation of an existing structure that was demolished to build the new
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/140px-Jerusalem-coat-of-arms.svg.png">
+ <alt>
+ The emblem of Jerusalem is a lion standing in front of the Western Wall and flanked by olive branches.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Matha.png">
+ <alt>
+ &quot;Bharat Mata&quot; (&quot;Mother India&quot;), National personification of India, depicted with an Asiatic/Indian lion at her side
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/240px-Flag_of_Sri_Lanka.svg.png">
+ <alt>
+ Flag of Sri Lanka
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Royal_Arms_of_Scotland.svg.png">
+ <alt>
+ Lion rampant on the royal coat of arms of Scotland
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/225px-Una-lion.jpg">
+ <alt>
+ The lion is a popular symbol and mascot of high schools, colleges and universities throughout the United States. This statue is on the campus of the University of North Alabama.
+ </alt>
+ </image>
+ </refbody>
+ </reference>
+</reference> \ No newline at end of file
diff --git a/Processing/demolibrary/tiger-wikipedia.dita b/Processing/demolibrary/tiger-wikipedia.dita
new file mode 100644
index 0000000..9f59b18
--- /dev/null
+++ b/Processing/demolibrary/tiger-wikipedia.dita
@@ -0,0 +1,2100 @@
+<?xml version='1.0' encoding='utf-8'?>
+<reference>
+ <title>
+ Tiger
+ </title>
+ <shortdesc>
+ <ph id="2">
+ The tiger (Panthera tigris) is a member of the Felidae family; the largest and the most powerful of the four "big cats"
+ </ph>
+ <ph id="3">
+ in the genus Panthera.
+ </ph>
+ <ph id="4">
+ Native to much of eastern and southern Asia, the tiger is an apex predator and an obligate carnivore.
+ </ph>
+ <ph id="5">
+ Reaching up to 4 metres (13 ft) in total length and weighing up to 300 kilograms (660 pounds), the larger tiger subspecies are comparable in size to the biggest extinct felids.
+ </ph>
+ <ph id="6">
+ Aside from their great bulk and power, their most recognizable feature is the pattern of dark vertical stripes that overlays near-white to reddish-orange fur, with lighter underparts.
+ </ph>
+ <ph id="7">
+ The largest subspecies of tiger is the Siberian tiger.
+ </ph>
+ </shortdesc>
+ <prolog>
+ <source href="http://en.wikipedia.org/w/index.php?oldid=234594733">
+ <publisher>
+ wikipedia.org
+ </publisher>
+ <critdates>
+ <created date="2008-09-05">
+ <revised modified="2008-09-05">
+ </revised>
+ </created>
+ </critdates>
+ </source>
+ </prolog>
+ <refbody>
+ <section id="infobox">
+ <title>
+ Scientific classification
+ </title>
+ <properties>
+ <property>
+ <proptype>
+ Kingdom
+ </proptype>
+ <propvalue>
+ Animalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Phylum
+ </proptype>
+ <propvalue>
+ Chordata
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Class
+ </proptype>
+ <propvalue>
+ Mammalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Order
+ </proptype>
+ <propvalue>
+ Carnivora
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Family
+ </proptype>
+ <propvalue>
+ Felidae
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Genus
+ </proptype>
+ <propvalue>
+ Panthera
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Species
+ </proptype>
+ <propvalue>
+ P. tigris
+ </propvalue>
+ </property>
+ </properties>
+ </section>
+ <p id="2">
+ <ph id="8">
+ Highly adaptable, tigers range from the Siberian taiga, to open grasslands, to tropical mangrove swamps.
+ </ph>
+ <ph id="9">
+ They are territorial and generally solitary animals, often requiring large contiguous areas of habitat that support their prey demands.
+ </ph>
+ <ph id="10">
+ This, coupled with the fact that they are endemic to some of the more densely populated places on earth, has caused significant conflicts with humans.
+ </ph>
+ <ph id="11">
+ Of the nine subspecies of modern tiger, three are extinct and the remaining six are classified as endangered, some critically so.
+ </ph>
+ <ph id="12">
+ The primary direct causes are habitat destruction and fragmentation, and hunting.
+ </ph>
+ <ph id="13">
+ Their historical range, which once reached from Mesopotamia and the Caucasus through most of South and East Asia, has been radically reduced.
+ </ph>
+ <ph id="14">
+ While all surviving species are under formal protection, poaching, habitat destruction and inbreeding depression continue to be threats.
+ </ph>
+ </p>
+ <p id="3">
+ <ph id="15">
+ Nonetheless, tigers are among the most recognizable and popular of the world's charismatic megafauna.
+ </ph>
+ <ph id="16">
+ They have featured prominently in ancient mythology and folklore, and continue to be depicted in modern films and literature.
+ </ph>
+ <ph id="17">
+ Tigers appear on many flags and coats of arms, as mascots for sporting teams, and as the national animal of several Asian nations.
+ </ph>
+ </p>
+ <p id="4">
+ <ph id="18">
+ </ph>
+ </p>
+ </refbody>
+ <reference id="2">
+ <title>
+ Naming and etymology
+ </title>
+ <refbody>
+ <p id="5">
+ <ph id="19">
+ The word "tiger"
+ </ph>
+ <ph id="20">
+ is taken from the Greek word "tigris", which is possibly derived from a Persian source meaning "arrow", a reference to the animal's speed and also the origin for the name of the River Tigris.
+ </ph>
+ <ph id="21">
+ In American English, "Tigress"
+ </ph>
+ <ph id="22">
+ was first recorded in 1611.
+ </ph>
+ <ph id="23">
+ It was one of the many species originally described, as Felis tigris, by Linnaeus in his 18th&amp;#160;century work, Systema Naturae.
+ </ph>
+ <ph id="24">
+ The generic component of its scientific designation, Panthera tigris, is often presumed to derive from Greek pan- ("all") and ther ("beast"), but this may be a folk etymology.
+ </ph>
+ <ph id="25">
+ Although it came into English through the classical languages, panthera is probably of East Asian origin, meaning "the yellowish animal,"
+ </ph>
+ <ph id="26">
+ or "whitish-yellow".
+ </ph>
+ </p>
+ <p id="6">
+ <ph id="27">
+ A group of tigers is rare (see below), but when seen together is termed a 'streak' or an 'ambush'.
+ </ph>
+ </p>
+ <p id="7">
+ <ph id="28">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="3">
+ <title>
+ Range
+ </title>
+ <refbody>
+ <p id="8">
+ <ph id="29">
+ In the historical past tigers were widespread in Asia, from the Caucasus and the Caspian Sea, to Siberia and Indonesia.
+ </ph>
+ <ph id="30">
+ During the 19th century the striped cats completely vanished from western Asia, and became restricted to isolated pockets in the remaining parts of their range.
+ </ph>
+ <ph id="31">
+ Today, this fragmented relic range extends from India in the west to China and Southeast Asia in the east.
+ </ph>
+ <ph id="32">
+ The northern limit is close to the Amur River in south eastern Siberia.
+ </ph>
+ <ph id="33">
+ The only large island inhabited by tigers today is Sumatra.
+ </ph>
+ <ph id="34">
+ Tigers vanished from Java during the second half of the 19th century, and in Borneo are known only from fossil remains.
+ </ph>
+ </p>
+ <p id="9">
+ <ph id="35">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="4">
+ <title>
+ Physical characteristics, taxonomy and evolution
+ </title>
+ <refbody>
+ <p id="10">
+ <ph id="36">
+ The oldest remains of a tiger-like cat, called Panthera palaeosinensis, have been found in China and Java.
+ </ph>
+ <ph id="37">
+ This species lived about 2 million years ago, at the beginning of the Pleistocene, and was smaller than a modern tiger.
+ </ph>
+ <ph id="38">
+ The earliest fossils of true tigers are known from Java, and are between 1.6 and 1.8 million years old.
+ </ph>
+ <ph id="39">
+ Distinct fossils from the early and middle Pleistocene were also discovered in deposits from China, and Sumatra.
+ </ph>
+ <ph id="40">
+ A subspecies called the Trinil tiger (Panthera tigris trinilensis) lived about 1.2 million years ago and is known fossils found at Trinil in Java.
+ </ph>
+ </p>
+ <p id="11">
+ <ph id="41">
+ Tigers first reached India and northern Asia in the late Pleistocene, reaching eastern Beringia (but not the American Continent), and Japan, and Sakhalin.
+ </ph>
+ <ph id="42">
+ Fossils found in Japan indicate that the local tigers were, like the surviving island subspecies, smaller than the mainland forms.
+ </ph>
+ <ph id="43">
+ This may be due to the phenomenon in which body size is related to environmental space (see insular dwarfism), or perhaps the availability of prey.
+ </ph>
+ <ph id="44">
+ Until the Holocene, tigers also lived in Borneo.
+ </ph>
+ </p>
+ <p id="12">
+ <ph id="45">
+ </ph>
+ </p>
+ <section id="2">
+ <title>
+ Physical characteristics
+ </title>
+ <p id="13">
+ <ph id="46">
+ Today, tigers are perhaps the most recognisable of all the cats (with the possible exception of the lion).
+ </ph>
+ <ph id="47">
+ They typically have rusty-reddish to brown-rusty coats, a whitish medial and ventral area, a white "fringe"
+ </ph>
+ <ph id="48">
+ that surrounds the face, and stripes that vary from brown or gray to pure black.
+ </ph>
+ <ph id="49">
+ The form and density of stripes differs between subspecies (as well as the ground coloration of the fur; for instance, Siberian tigers are usually paler than other tiger subspecies), but most tigers have over 100 stripes.
+ </ph>
+ <ph id="50">
+ The pattern of stripes is unique to each animal, and thus could potentially be used to identify individuals, much in the same way as fingerprints are used to identify people.
+ </ph>
+ <ph id="51">
+ This is not, however, a preferred method of identification, due to the difficulty of recording the stripe pattern of a wild tiger.
+ </ph>
+ <ph id="52">
+ It seems likely that the function of stripes is camouflage, serving to help tigers conceal themselves amongst the dappled shadows and long grass of their environment as they stalk their prey.
+ </ph>
+ <ph id="53">
+ The stripe pattern is found on a tiger's skin and if shaved, its distinctive camouflage pattern would be preserved.
+ </ph>
+ <ph id="54">
+ Like other big cats, tigers have a white spot on the backs of their ears.
+ </ph>
+ </p>
+ <p id="14">
+ <ph id="55">
+ Tigers have the additional distinction of being the heaviest cats found in the wild.
+ </ph>
+ <ph id="56">
+ However, the subspecies differ markedly in size, tending to increase proportionally with latitude, as predicted by Bergmann's Rule.
+ </ph>
+ <ph id="57">
+ Thus, large male Siberian Tigers (Panthera tigris altaica) can reach a total length of 3.5&amp;#160;m and a weight of 306&amp;#160;kilograms, which is considerably larger than the sizes reached by island-dwelling tigers such as the Sumatran, the smallest living subspecies with an body weight of only 75-140 kg.
+ </ph>
+ <ph id="58">
+ Tigresses are smaller than the males in each subspecies, although the size difference between male and female tigers tends to be more pronounced in the larger subspecies of tiger, with males weighing up to 1.7 times as much as the females.
+ </ph>
+ <ph id="59">
+ In addition, male tigers have wider forepaw pads than females.
+ </ph>
+ <ph id="60">
+ This difference is often used by biologists in determining the gender of tigers when observing their tracks.
+ </ph>
+ </p>
+ <p id="15">
+ <ph id="61">
+ </ph>
+ </p>
+ </section>
+ <section id="3">
+ <title>
+ Subspecies
+ </title>
+ <p id="16">
+ <ph id="62">
+ There are nine recent subspecies of tiger, three of which are extinct.
+ </ph>
+ <ph id="63">
+ Their historical range (severely diminished today) ran through Bangladesh, Siberia, Iran, Afghanistan, India, China, and southeast Asia, including some Indonesian islands.
+ </ph>
+ <ph id="64">
+ The surviving subspecies, in descending order of wild population, are:
+ </ph>
+ </p>
+ <ul>
+ <li>
+ The Bengal tiger or the Royal Bengal tiger (Panthera tigris tigris) is found in parts of India, Bangladesh, Nepal, Bhutan, and Burma. It lives in varied habitats: grasslands, subtropical and tropical rainforests, scrub forests, wet and dry deciduous forests, and mangroves. Males in the wild usually weigh 205 to 227&amp;#160;kg (450–500&amp;#160;lb), while the average female will weigh about 141&amp;#160;kg. However, the northern Indian and the Nepalese Bengal tigers are somewhat bulkier than those found in the south of the Indian Subcontinent, with males averaging around 236 kg (520 lb). While conservationists already believed the population to be below 2,000, the most recent audit by the Indian Government's National Tiger Conservation Authority has estimated the number at just 1,411 wild tigers (1165-1657 allowing for statistical error), a drop of 60% in the past decade. Since 1972, there has been a massive wildlife conservation project, known as Project Tiger, to protect the Bengal tiger. The project is considered as one of the most successful wildlife conservation programs, though at least one Tiger Reserve (Sariska Tiger Reserve) has lost its entire tiger population to poaching.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The Indochinese tiger (Panthera tigris corbetti), also called Corbett's tiger, is found in Cambodia, China, Laos, Burma, Thailand, and Vietnam. These tigers are smaller and darker than Bengal tigers: Males weigh from 150–190&amp;#160;kg (330–420&amp;#160;lb) while females are smaller at 110–140&amp;#160;kg (242–308&amp;#160;lb). Their preferred habitat is forests in mountainous or hilly regions. Estimates of the Indochinese tiger population vary between 1,200 to 1,800, with only several hundred left in the wild. The largest current population is in Malaysia, where illegal poaching is strictly controlled, but all existing populations are at extreme risk from habitat fragmentation and inbreeding. In Vietnam, almost three-quarters of the tigers killed provide stock for Chinese pharmacies.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The Malayan tiger (Panthera tigris malayensis), exclusively found in the southern part of the Malay Peninsula, was not considered a subspecies in its own right until 2004. The new classification came about after a study by Luo et al. from the Laboratory of Genomic Diversity Study, part of the National Cancer Institute of the United States. Recent counts showed there are 600–800 tigers in the wild, making it the third largest tiger population, behind the Bengal tiger and the Indochinese tiger. The Malayan tiger is the smallest of the mainland tiger subspecies, and the second smallest living subspecies, with males averaging about 120 kg and females about 100 kg in weight. The Malayan tiger is a national icon in Malaysia, appearing on its coat of arms and in logos of Malaysian institutions, such as Maybank.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The Sumatran tiger (Panthera tigris sumatrae) is found only on the Indonesian island of Sumatra, and is critically endangered. It is the smallest of all living tiger subspecies, with adult males weighing between 100–140&amp;#160;kg (220–308&amp;#160;lb) and females 75–110&amp;#160;kg (154–242&amp;#160;lb). Their small size is an adaptation to the thick, dense forests of the island of Sumatra where they reside, as well as the smaller-sized prey. The wild population is estimated at between 400 and 500, seen chiefly in the island's national parks. Recent genetic testing has revealed the presence of unique genetic markers, indicating that it may develop into a separate species, if it does not go extinct. This has led to suggestions that Sumatran tigers should have greater priority for conservation than any other subspecies. While Habitat destruction is the main threat to the existing tiger population (logging continues even in the supposedly protected national parks), 66 tigers were recorded as being shot and killed between 1998 and 2000, or nearly 20% of the total population.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The Siberian tiger (Panthera tigris altaica), also known as the Amur, Manchurian, Altaic, Korean or North China tiger, is confined to the Amur-Ussuri region of Primorsky Krai and Khabarovsk Krai in far eastern Siberia, where it is now protected. Considered the largest subspecies, with a head and body length of 190–220&amp;#160;cm (the tail of a tiger is 60–110&amp;#160;cm long) and an average weight of around 227&amp;#160;kg (500&amp;#160;lb) for males, the Amur tiger is also noted for its thick coat, distinguished by a paler golden hue and fewer stripes. The heaviest wild Siberian tiger on record weighed in at 384 kg, but according to Mazak these giants are not confirmed via reliable references. Even so, a six-month old Siberian tiger can be as big as a fully grown leopard. The last two censuses (1996 and 2005) found 450–500 Amur tigers within their single, and more or less continuous, range making it one of the largest undivided tiger populations in the world.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The South China tiger (Panthera tigris amoyensis), also known as the Amoy or Xiamen tiger, is the most critically endangered subspecies of tiger and is listed as one of the 10 most endangered species in the world. It will almost certainly become extinct. One of the smaller tiger subspecies, the length of the South China tiger ranges from 2.2–2.6&amp;#160;m (87–104&amp;#160;in) for both males and females. Males weigh between 127 and 177&amp;#160;kg (280–390&amp;#160;lb) while females weigh between 100 and 118&amp;#160;kg (220–260&amp;#160;lb). From 1983 to 2007, no South China tigers were sighted. In 2007 a farmer spotted a tiger and handed in photographs to the authorities as proof. In 1977, the Chinese government passed a law banning the killing of wild tigers, but this may have been too late to save the subspecies. There are currently 59 known captive South China tigers, all within China, but these are known to be descended from only six animals. Thus, the genetic diversity required to maintain the subspecies may no longer exist. Currently, there are breeding efforts to reintroduce these tigers to the wild by 2008.
+ </li>
+ </ul>
+ <p id="17">
+ <ph id="65">
+ </ph>
+ </p>
+ </section>
+ <section id="4">
+ <title>
+ Extinct subspecies
+ </title>
+ <ul>
+ <li>
+ The Balinese tiger (Panthera tigris balica) was limited to the island of Bali. They were the smallest of all tiger subspecies, with a weight of 90–100&amp;#160;kg in males and 65–80&amp;#160;kg in females. These tigers were hunted to extinction—the last Balinese tiger is thought to have been killed at Sumbar Kima, West Bali on 27 September 1937; this was an adult female. No Balinese tiger was ever held in captivity. The tiger still plays an important role in Balinese Hindu religion.
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The Javan tiger (Panthera tigris sondaica) was limited to the Indonesian island of Java. It now seems likely that this subspecies became extinct in the 1980s, as a result of hunting and habitat destruction, but the extinction of this subspecies was extremely probable from the 1950s onwards (when it is thought that fewer than 25 tigers remained in the wild). The last confirmed specimen was sighted in 1979, but there were a few reported sightings during the 1990s. With a weight of 100-141 kg for males and 75-115 kg for females, the Javan tiger was one of the smaller subspecies, approximately the same size as the Sumatran tiger
+ </li>
+ </ul>
+ <ul>
+ <li>
+ The Caspian tiger or Persian tiger (Panthera tigris virgata) appears to have become extinct in the wild in the late 1950s, with the last reliable sighting in 1968, though it is thought that such a tiger was last shot dead in the south-eastern-most part of Turkey in 1970. Historically, it ranged through Afghanistan, Iran, Iraq, Pakistan, the former Soviet Union, and Turkey. The Caspian tiger was a large subspecies and reached nearly the dimensions of the Bengal Tiger. The heaviest confirmed weight of a male was 240&amp;#160;kg. The ground colour was comparable to that of the Indian subspecies, but differed especially in the tight, narrow, striping pattern. The stripes were dark grey or brown, rather than black. Especially during the winter, the fur was relatively long. The Caspian tiger was one of two subspecies of tiger (along with the Bengal) that was used by the Romans to battle gladiators and other animals, including the Barbary Lion. The Romans traveled far to capture exotic beasts for the arena. There are still occasional reported sightings of the Caspian Tiger in the wild.
+ </li>
+ </ul>
+ <p id="18">
+ <ph id="66">
+ </ph>
+ </p>
+ </section>
+ <section id="5">
+ <title>
+ Hybrids
+ </title>
+ <p id="19">
+ <ph id="67">
+ Hybridization among the big cats, including the tiger, was first conceptualized in the 19th century, when zoos were particularly interested in the pursuit of finding oddities to display for financial gain.
+ </ph>
+ <ph id="68">
+ Lions have been known to breed with tigers (most often the Amur and Bengal subspecies) to create hybrids called ligers and tigons.
+ </ph>
+ <ph id="69">
+ Such hybrids were once commonly bred in zoos, but this is now discouraged due to the emphasis on conserving species and subspecies.
+ </ph>
+ <ph id="70">
+ Hybrids are still bred in private menageries and in zoos in China.
+ </ph>
+ </p>
+ <p id="20">
+ <ph id="71">
+ The liger is a cross between a male lion and a tigress.
+ </ph>
+ <ph id="72">
+ Because the lion sire passes on a growth-promoting gene, but the corresponding growth-inhibiting gene from the female tiger is absent, ligers grow far larger than either parent.
+ </ph>
+ <ph id="73">
+ They share physical and behavioural qualities of both parent species (spots and stripes on a sandy background).
+ </ph>
+ <ph id="74">
+ Male ligers are sterile, but female ligers are often fertile.
+ </ph>
+ <ph id="75">
+ Males have about a 50% chance of having a mane, but, even if they do, their manes will be only around half the size of that of a pure lion.
+ </ph>
+ <ph id="76">
+ Ligers are typically between 10 to 12 feet in length, and can be between 800 and 1,000 pounds or more.
+ </ph>
+ </p>
+ <p id="21">
+ <ph id="77">
+ The less common tigon is a cross between the lioness and the male tiger.
+ </ph>
+ </p>
+ <p id="22">
+ <ph id="78">
+ </ph>
+ </p>
+ </section>
+ <section id="6">
+ <title>
+ Colour variations
+ </title>
+ <p id="23">
+ <ph id="79">
+ </ph>
+ </p>
+ </section>
+ <section id="7">
+ <title>
+ White tigers
+ </title>
+ <p id="24">
+ <ph id="80">
+ There is a well-known mutation that produces the white tiger, technically known as chinchilla albinistic, an animal which is rare in the wild, but widely bred in zoos due to its popularity.
+ </ph>
+ <ph id="81">
+ Breeding of white tigers will often lead to inbreeding (as the trait is recessive).
+ </ph>
+ <ph id="82">
+ Many initiatives have taken place in white and orange tiger mating in an attempt to remedy the issue, often mixing subspecies in the process.
+ </ph>
+ <ph id="83">
+ Furthermore, such inbreeding has led to white tigers having a greater likelihood of being born with physical defects, such as crossed eyes, cleft palates and scoliosis (curvature of the spine).
+ </ph>
+ <ph id="84">
+ Even apparently healthy white tigers generally do not live as long as their orange counterparts.
+ </ph>
+ </p>
+ <p id="25">
+ <ph id="85">
+ Recordings of white tigers were first made in the early 19th century.
+ </ph>
+ <ph id="86">
+ They can only occur when both parents carry the rare gene found in white tigers; this gene has been calculated to occur in only one in every 10,000 births.
+ </ph>
+ <ph id="87">
+ The white tiger is not a separate sub-species, but only a colour variation; since the only white tigers that have been observed in the wild have been Bengal tigers (and all white tigers in captivity are at least part Bengal), it is commonly thought that the recessive gene that causes the white colouring is probably carried only by Bengal tigers, although the reasons for this are not known.
+ </ph>
+ <ph id="88">
+ Nor are they in any way more endangered than tigers are generally, this being a common misconception.
+ </ph>
+ <ph id="89">
+ Another misconception is that white tigers are albinos, despite the fact that pigment is evident in the white tiger's stripes.
+ </ph>
+ <ph id="90">
+ They are distinct not only because of their white hue; they also have blue eyes and pink noses.
+ </ph>
+ </p>
+ <p id="26">
+ <ph id="91">
+ </ph>
+ </p>
+ </section>
+ <section id="8">
+ <title>
+ Golden tabby tigers
+ </title>
+ <p id="27">
+ <ph id="92">
+ In addition, another recessive gene may create a very unusual "golden tabby"
+ </ph>
+ <ph id="93">
+ colour variation, sometimes known as "strawberry".
+ </ph>
+ <ph id="94">
+ Golden tabby tigers have light gold fur, pale legs and faint orange stripes.
+ </ph>
+ <ph id="95">
+ Their fur tends to be much thicker than normal.
+ </ph>
+ <ph id="96">
+ There are extremely few golden tabby tigers in captivity, around 30 in all.
+ </ph>
+ <ph id="97">
+ Like white tigers, strawberry tigers are invariably at least part Bengal.
+ </ph>
+ <ph id="98">
+ Both white and golden tabby tigers tend to be larger than average Bengal tigers.
+ </ph>
+ </p>
+ <p id="28">
+ <ph id="99">
+ </ph>
+ </p>
+ </section>
+ <section id="9">
+ <title>
+ Other colour variations
+ </title>
+ <p id="29">
+ <ph id="100">
+ There are also unconfirmed reports of a "blue"
+ </ph>
+ <ph id="101">
+ or slate-coloured tiger, and largely or totally black tigers, and these are assumed, if real, to be intermittent mutations rather than distinct species.
+ </ph>
+ </p>
+ <p id="30">
+ <ph id="102">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="5">
+ <title>
+ Biology and behaviour
+ </title>
+ <refbody>
+ <p id="31">
+ <ph id="103">
+ </ph>
+ </p>
+ <section id="10">
+ <title>
+ Territorial behavior
+ </title>
+ <p id="32">
+ <ph id="104">
+ Adult tigers are fiercely territorial.
+ </ph>
+ <ph id="105">
+ The size of a tiger's home range mainly depends on prey abundance, and, in the case of male tigers, on access to females.
+ </ph>
+ <ph id="106">
+ A tigress may have a territory of 20&amp;#160;square kilometres while the territories of males are much larger, covering 60–100&amp;#160;km².
+ </ph>
+ <ph id="107">
+ While females can at times be aggressive towards other females, their territories can overlap and they do tolerate each other.
+ </ph>
+ <ph id="108">
+ Males, however, are usually intolerant of other males within their territory.
+ </ph>
+ <ph id="109">
+ Because of their aggressive nature, territorial disputes can be violent, and may end in the death of one of the males.
+ </ph>
+ <ph id="110">
+ To identify his territory, the male marks trees by spraying of urine and anal gland secretions, as well as marking trails with scat.
+ </ph>
+ <ph id="111">
+ Males show a grimacing face, called the Flehmen response, when identifying a female's reproductive condition by sniffing their urine markings.
+ </ph>
+ </p>
+ <p id="33">
+ <ph id="112">
+ Male tigers can mingle easily with females in their territories, and will even share kills.
+ </ph>
+ <ph id="113">
+ George Schaller observed a male tiger share a kill with two females and four cubs.
+ </ph>
+ <ph id="114">
+ Females are often reluctant to let males near their cubs, but Schaller saw that these females made no effort to protect or keep their cubs from the male.
+ </ph>
+ <ph id="115">
+ This suggests that the male might have been the father of the cubs.
+ </ph>
+ <ph id="116">
+ In contrast to male lions, male tigers will allow the females and cubs to feed on the kill first.
+ </ph>
+ <ph id="117">
+ Females will also share kills, even more so than the males.
+ </ph>
+ <ph id="118">
+ They are also much more tolerant of sharing kills with individuals of the same sex.
+ </ph>
+ </p>
+ <p id="34">
+ <ph id="119">
+ Tigers have been studied in the wild using a variety of techniques.
+ </ph>
+ <ph id="120">
+ The populations of tigers were estimated in the past using plaster casts of their pugmarks.
+ </ph>
+ <ph id="121">
+ This method was found faulty and attempts were made to use camera trapping instead.
+ </ph>
+ <ph id="122">
+ Newer techniques based on DNA from their scat are also being evaluated.
+ </ph>
+ <ph id="123">
+ Radio collaring has also been a popular approach to tracking them for study in the wild.
+ </ph>
+ </p>
+ <p id="35">
+ <ph id="124">
+ </ph>
+ </p>
+ </section>
+ <section id="11">
+ <title>
+ Hunting and diet
+ </title>
+ <p id="36">
+ <ph id="125">
+ In the wild, tigers mostly feed on larger and medium sized animals.
+ </ph>
+ <ph id="126">
+ Sambar, gaur, domestic buffalo, chital, boar, and nilgai are the tiger's favored prey in India.
+ </ph>
+ <ph id="127">
+ Sometimes, they also prey on leopards, pythons, sloth bears and crocodiles.
+ </ph>
+ <ph id="128">
+ In Siberia the main prey species are Mandchurian elk, wild boar, Sika Deer, roe deer, and musk deer.
+ </ph>
+ <ph id="129">
+ In Sumatra Rusa Deer, wild boar, and Malayan Tapir are preyed on.
+ </ph>
+ <ph id="130">
+ In the former Caspian tiger's range, prey included Saiga Antelope, camels, Caucasian Wisent, yak, and wild horses.
+ </ph>
+ <ph id="131">
+ Like many predators, they are opportunistic and will eat much smaller prey, such as monkeys, peafowls, hares, and fish.
+ </ph>
+ </p>
+ <p id="37">
+ <ph id="132">
+ Adult elephants are too large to serve as common prey, but conflicts between tigers and elephants do sometimes take place.
+ </ph>
+ <ph id="133">
+ A case where a tiger killed an adult Indian Rhinoceros has been observed.
+ </ph>
+ <ph id="134">
+ Young elephant and rhino calves are occasionally taken.
+ </ph>
+ <ph id="135">
+ Tigers also sometimes prey on domestic animals such as dogs, cows, horses, and donkeys.
+ </ph>
+ <ph id="136">
+ These individuals are termed cattle-lifters or cattle-killers in contrast to typical game-killers.
+ </ph>
+ </p>
+ <p id="38">
+ <ph id="137">
+ Old tigers, or those wounded and rendered incapable of catching their natural prey, have turned into man-eaters; this pattern has recurred frequently across India.
+ </ph>
+ <ph id="138">
+ An exceptional case is that of the Sundarbans, where healthy tigers prey upon fishermen and villagers in search of forest produce, humans thereby forming a minor part of the Tiger's diet.
+ </ph>
+ </p>
+ <p id="39">
+ <ph id="139">
+ Tigers usually hunt at night.
+ </ph>
+ <ph id="140">
+ They generally hunt alone and ambush their prey as most other cats do, overpowering them from any angle, using their body size and strength to knock large prey off balance.
+ </ph>
+ <ph id="141">
+ Even with their great masses, tigers can reach speeds of about 49-65&amp;#160;kilometres per hour (35-40&amp;#160;miles per hour), although they can only do so in short bursts; consequently, tigers must be relatively close to their prey before they break their cover.
+ </ph>
+ <ph id="142">
+ In addition, tigers can leap as high as 5&amp;#160;m (16&amp;#160;ft) and as far as 9–10&amp;#160;m (30–33&amp;#160;ft), making them one of the highest-jumping mammals, just slightly behind cougars in ability.
+ </ph>
+ <ph id="143">
+ They have been reported to carry domestic livestock weighing 50&amp;#160;kg (110&amp;#160;lb) while easily jumping over fences 2&amp;#160;m (6&amp;#160;ft 6&amp;#160;in) high.
+ </ph>
+ <ph id="144">
+ Even so, only one in twenty hunts ends in a successful kill.
+ </ph>
+ </p>
+ <p id="40">
+ <ph id="145">
+ When hunting large prey, tigers prefer to bite the throat and use their muscled forelimbs to hold onto the prey, bringing it to the ground.
+ </ph>
+ <ph id="146">
+ Their heavily muscled forelimbs are used to hold tightly onto the prey and to avoid being dislodged.
+ </ph>
+ <ph id="147">
+ The tiger remains latched onto the neck until its prey dies of strangulation.
+ </ph>
+ <ph id="148">
+ By this method, gaurs and water buffalos weighing over a ton have been killed by tigers weighing about a sixth as much.
+ </ph>
+ <ph id="149">
+ With small prey, the tiger bites the nape, often breaking the spinal cord, piercing the windpipe, or severing the jugular vein or common carotid artery.
+ </ph>
+ <ph id="150">
+ Though rarely observed, some tigers have been recorded to kill prey by swiping with their paws, which are powerful enough to smash the skulls of domestic cattle, and break the backs of sloth bears.
+ </ph>
+ </p>
+ <p id="41">
+ <ph id="151">
+ Tigers will occasionally eat vegetation for dietary fiber, the fruit of the Slow Match Tree being favoured.
+ </ph>
+ </p>
+ <p id="42">
+ <ph id="152">
+ </ph>
+ </p>
+ </section>
+ <section id="12">
+ <title>
+ Interspecific predatory relationships
+ </title>
+ <p id="43">
+ <ph id="153">
+ Tigers may kill such formidable predators as leopards, pythons and even crocodiles on occasion, although predators typically avoid one another.
+ </ph>
+ <ph id="154">
+ When seized by a crocodile, a tiger will strike at the reptile's eyes with its paws.
+ </ph>
+ <ph id="155">
+ Leopards dodge competition from tigers by hunting in different times of the day and hunting different prey.
+ </ph>
+ <ph id="156">
+ With relatively abundant prey, tigers and leopards were seen to successfully coexist without competitive exclusion or inter-species dominance hierarchies that may be more common to the savanna.
+ </ph>
+ <ph id="157">
+ Tigers have been known to suppress wolf populations in areas where the two species coexist.
+ </ph>
+ <ph id="158">
+ Dhole packs have been observed to attack and kill tigers in disputes over food, though not usually without heavy losses.
+ </ph>
+ <ph id="159">
+ Siberian tigers and brown bears can be competitors and usually avoid confrontation; however, tigers will kill bear cubs and even some adults on occasion.
+ </ph>
+ <ph id="160">
+ Bears (Asiatic black bears and brown bears) make up 5-8% of the Tiger's diet in the Russian Far East.
+ </ph>
+ <ph id="161">
+ Some bears emerging from hibernation will try to steal tigers' kills, although the tiger will mostly defend its kill.
+ </ph>
+ <ph id="162">
+ Sloth bears are quite aggressive and will sometimes drive younger aged tigers away from their kills, although in most of cases Bengal tigers prey on sloth bears.
+ </ph>
+ </p>
+ <p id="44">
+ <ph id="163">
+ </ph>
+ </p>
+ </section>
+ <section id="13">
+ <title>
+ Reproduction
+ </title>
+ <p id="45">
+ <ph id="164">
+ A female is only receptive for a few days and mating is frequent during that time period.
+ </ph>
+ <ph id="165">
+ A pair will copulate frequently and noisily, like other cats.
+ </ph>
+ <ph id="166">
+ The gestation period is 16 weeks and 3–4 cubs of about 1&amp;#160;kg (2&amp;#160;lb) each are born.
+ </ph>
+ <ph id="167">
+ The females rear them alone.
+ </ph>
+ <ph id="168">
+ Wandering male tigers may kill cubs to make the female receptive.
+ </ph>
+ <ph id="169">
+ At 8 weeks, the cubs are ready to follow their mother out of the den.
+ </ph>
+ <ph id="170">
+ The cubs become independent around 18 months of age, but it is not until they are around 2–2½ years old that they leave their mother.
+ </ph>
+ <ph id="171">
+ The cubs reach sexual maturity by 3–4 years of age.
+ </ph>
+ <ph id="172">
+ The female tigers generally own territory near their mother, while males tend to wander in search of territory, which they acquire by fighting and eliminating another male.
+ </ph>
+ <ph id="173">
+ Over the course of her life, a female tiger will give birth to an approximately equal number of male and female cubs.
+ </ph>
+ <ph id="174">
+ Tigers breed well in captivity, and the captive population in the United States may rival the wild population of the world.
+ </ph>
+ </p>
+ <p id="46">
+ <ph id="175">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="6">
+ <title>
+ Habitat
+ </title>
+ <refbody>
+ <p id="47">
+ <ph id="176">
+ Typical tiger country has three main features: It will always have good cover, it will always be close to water and plenty of prey.
+ </ph>
+ <ph id="177">
+ Bengal Tigers live in all types of forests, including Wet, Evergreen, semi-evergreen of Assam and eastern Bengal; the mangrove forest of Ganges Delta; The deciduous forest of Nepal and thorn forests of the Western Ghats.
+ </ph>
+ <ph id="178">
+ Compared to the lion, the tiger prefers more dense vegetation, for which its camouflage is ideally suited, and where a single predator is not at a disadvantage compared to a pride.
+ </ph>
+ <ph id="179">
+ Among the big cats, only the tiger and jaguar are strong swimmers; tigers are often found bathing in ponds, lakes, and rivers.
+ </ph>
+ <ph id="180">
+ Unlike other cats, which tend to avoid water, tigers actively seek it out.
+ </ph>
+ <ph id="181">
+ During the extreme heat of the day, they are often to be found cooling off in pools.
+ </ph>
+ <ph id="182">
+ Tigers are excellent swimmers, better than the jaguar and can swim up to 4 miles.
+ </ph>
+ <ph id="183">
+ Tigers are often to be found carrying their dead prey across lakes.
+ </ph>
+ </p>
+ <p id="48">
+ <ph id="184">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="7">
+ <title>
+ Conservation efforts
+ </title>
+ <refbody>
+ <p id="49">
+ <ph id="185">
+ Poaching for fur and destruction of habitat have greatly reduced tiger populations in the wild.
+ </ph>
+ <ph id="186">
+ A century ago, it is estimated there were over 100,000 tigers in the world but the population has dwindled to between 7,000 and 5,000 tigers.
+ </ph>
+ <ph id="187">
+ Some estimates suggest the population is even lower, with some at less than 2,500 mature breeding individuals, with no subpopulation containing more than 250 mature breeding individuals.
+ </ph>
+ <ph id="188">
+ The threat of extinction is mitigated somewhat by the presence of some 20,000 tigers currently in captivity, although parts of the captive population, such as the 4-5,000 animals in China's commercial tiger farms, are of low genetic diversity.
+ </ph>
+ </p>
+ <p id="50">
+ <ph id="189">
+ </ph>
+ </p>
+ <section id="14">
+ <title>
+ India
+ </title>
+ <p id="51">
+ <ph id="190">
+ India harbors the largest population of wild tigers in the world, along with one of the highest human populations.
+ </ph>
+ <ph id="191">
+ A major concerted conservation effort known as Project Tiger has been underway since 1973, spearheaded by Indira Gandhi.
+ </ph>
+ <ph id="192">
+ The fundamental accomplishment has been the establishment of over 25 well-monitored tiger reserves in reclaimed land where human development is categorically forbidden.
+ </ph>
+ <ph id="193">
+ The program has been credited with tripling the number of wild Bengal tigers from roughly 1,200 in 1973 to over 3,500 in the 1990s, though the reports of the Indian government are occasionally met with some skepticism.
+ </ph>
+ <ph id="194">
+ A recently passed tribal Bill, which allows tribal populations to reside inside designated tiger sanctuaries, may have impacts on the continuing success of the program.
+ </ph>
+ </p>
+ <p id="52">
+ <ph id="195">
+ A tiger census carried out over 2007, whose report was published on February 12, 2008 stated that the wild tiger population in India has come down to approximately 1,411.
+ </ph>
+ <ph id="196">
+ It is noted in the report that the decrease of tiger population can be attributed directly to poaching.
+ </ph>
+ </p>
+ <p id="53">
+ <ph id="197">
+ </ph>
+ </p>
+ </section>
+ <section id="15">
+ <title>
+ Russia
+ </title>
+ <p id="54">
+ <ph id="198">
+ The Siberian tiger was on the brink of extinction with only about 40 animals in the wild in the 1940s.
+ </ph>
+ <ph id="199">
+ Under the Soviet Union, anti-poaching controls were strict and a network of protected zones (zapovedniks) were instituted, leading to a rise in the population to several hundred.
+ </ph>
+ <ph id="200">
+ Poaching again became a problem in the 1990s, when the economy of Russia collapsed, local hunters had access to a formerly sealed off lucrative Chinese market, and logging in the region increased.
+ </ph>
+ <ph id="201">
+ While an improvement in the local economy has led to greater resources being invested in conservation efforts, an increase of economic activity has led to an increased rate of development and deforestation.
+ </ph>
+ <ph id="202">
+ The major obstacle in preserving the species is the enormous territory individual tigers require (up to 450 km
+ <sup>
+ 2
+ </sup>
+ needed by a single female).
+ </ph>
+ <ph id="203">
+ Current conservation efforts are led by local governments and NGO's in consort with international organizations, such as the World Wide Fund and the Wildlife Conservation Society.
+ </ph>
+ <ph id="204">
+ Currently, there are about 400-550 animals in the wild.
+ </ph>
+ </p>
+ <p id="55">
+ <ph id="205">
+ </ph>
+ </p>
+ </section>
+ <section id="16">
+ <title>
+ Tibet
+ </title>
+ <p id="56">
+ <ph id="206">
+ In Tibet, tiger and leopard pelts have traditionally been used in various ceremonies and costumes.
+ </ph>
+ <ph id="207">
+ In January 2006 the Dalai Lama preached a ruling against using, selling, or buying wild animals, their products, or derivatives.
+ </ph>
+ <ph id="208">
+ It has yet to be seen whether this will result in a long-term slump in the demand for poached tiger and leopard skins.
+ </ph>
+ </p>
+ <p id="57">
+ <ph id="209">
+ </ph>
+ </p>
+ </section>
+ <section id="17">
+ <title>
+ Rewilding
+ </title>
+ <p id="58">
+ <ph id="210">
+ The first attempt at rewilding was by Indian conservationist Billy Arjan Singh, who reared a zoo-born tigress named Tara, and released her in the wilds of Dudhwa National Park in 1978.
+ </ph>
+ <ph id="211">
+ This was soon followed by a large number of people being eaten by a tigress who was later shot.
+ </ph>
+ <ph id="212">
+ Government officials claim that this tigress was Tara, an assertion hotly contested by Singh and conservationists.
+ </ph>
+ <ph id="213">
+ Later on, this rewilding gained further disrepute when it was found that the local gene pool had been sullied by Tara's introduction as she was partly Siberian tiger, a fact not known at the time of release, ostensibly due to poor record-keeping at Twycross Zoo, where she had been raised.
+ </ph>
+ </p>
+ <p id="59">
+ <ph id="214">
+ </ph>
+ </p>
+ </section>
+ <section id="18">
+ <title>
+ Save China's Tigers
+ </title>
+ <p id="60">
+ <ph id="215">
+ The organisation Save China's Tigers, working with the Wildlife Research Centre of the State Forestry Administration of China and the Chinese Tigers South Africa Trust, secured an agreement on the reintroduction of Chinese tigers into the wild.
+ </ph>
+ <ph id="216">
+ The agreement, which was signed in Beijing on 26 November 2002, calls for the establishment of a Chinese tiger conservation model through the creation of a pilot reserve in China where indigenous wildlife, including the South China Tiger, will be reintroduced.
+ </ph>
+ <ph id="217">
+ A number of Chinese tiger cubs will be selected from zoos in China and sent to a 300 square kilometer reserve near the town of Philippolis in South Africa, where they will be taught to hunt for themselves.
+ </ph>
+ <ph id="218">
+ The offspring of the trained tigers will be released into the pilot reserves in China, while the original animals will stay in South Africa to continue breeding.
+ </ph>
+ <ph id="219">
+ A second Chinese tiger rehabilitation project is also being run in Fujian, China.
+ </ph>
+ </p>
+ <p id="61">
+ <ph id="220">
+ China will conduct the work of surveying land, restoring habitat and prey within the pilot reserve.
+ </ph>
+ <ph id="221">
+ </ph>
+ </p>
+ <p id="62">
+ <ph id="222">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="8">
+ <title>
+ Relation with humans
+ </title>
+ <refbody>
+ <p id="63">
+ <ph id="223">
+ </ph>
+ </p>
+ <section id="19">
+ <title>
+ Tiger as prey
+ </title>
+ <p id="64">
+ <ph id="224">
+ The tiger has been one of the Big Five game animals of Asia.
+ </ph>
+ <ph id="225">
+ Tiger hunting took place on a large scale in the early nineteenth and twentieth centuries, being a recognised and admired sport by the British in colonial India as well as the maharajas and aristocratic class of the erstwhile princely states of pre-independence India.
+ </ph>
+ <ph id="226">
+ Tiger hunting was done by some hunters on foot; others sat up on machans with a goat or buffalo tied out as bait; yet others on elephant-back.
+ </ph>
+ <ph id="227">
+ In some cases, villagers beating drums were organised to drive the animals into the killing zone.
+ </ph>
+ <ph id="228">
+ Elaborate instructions were available for the skinning of tigers and there were taxidermists who specialised in the preparation of tiger skins.
+ </ph>
+ </p>
+ <p id="65">
+ <ph id="229">
+ </ph>
+ </p>
+ </section>
+ <section id="20">
+ <title>
+ Man-eating tigers
+ </title>
+ <p id="66">
+ <ph id="230">
+ Although humans are not regular prey for tigers, they have killed more people than any other cat, particularly in areas where population growth, logging, and farming have put pressure on tiger habitats.
+ </ph>
+ <ph id="231">
+ Most man-eating tigers are old and missing teeth, acquiring a taste for humans because of their inability to capture preferred prey.
+ </ph>
+ <ph id="232">
+ Almost all tigers that are identified as man-eaters are quickly captured, shot, or poisoned.
+ </ph>
+ <ph id="233">
+ Unlike man-eating leopards, even established man-eating tigers will seldom enter human settlements, usually remaining at village outskirts.
+ </ph>
+ <ph id="234">
+ Nevertheless, attacks in human villages do occur.
+ </ph>
+ <ph id="235">
+ Man-eaters have been a particular problem in India and Bangladesh, especially in Kumaon, Garhwal and the Sundarbans mangrove swamps of Bengal, where some healthy tigers have been known to hunt humans.
+ </ph>
+ </p>
+ <p id="67">
+ <ph id="236">
+ </ph>
+ </p>
+ </section>
+ <section id="21">
+ <title>
+ Traditional Asian medicine
+ </title>
+ <p id="68">
+ <ph id="237">
+ Many people in China have a belief that various tiger parts have medicinal properties, including as pain killers and aphrodisiacs.
+ </ph>
+ <ph id="238">
+ There is no scientific evidence to support these beliefs.
+ </ph>
+ <ph id="239">
+ The use of tiger parts in pharmaceutical drugs in China is already banned, and the government has made some offenses in connection with tiger poaching punishable by death.
+ </ph>
+ <ph id="240">
+ Furthermore, all trade in tiger parts is illegal under the Convention on International Trade in Endangered Species of Wild Fauna and Flora and a domestic trade ban has been in place in China since 1993.
+ </ph>
+ <ph id="241">
+ Still, there are a number of tiger farms in the country specializing in breeding the cats for profit.
+ </ph>
+ <ph id="242">
+ It is estimated that between 4,000 and 5,000 captive-bred, semi-tame animals live in these farms today.
+ </ph>
+ </p>
+ <p id="69">
+ <ph id="243">
+ </ph>
+ </p>
+ </section>
+ <section id="22">
+ <title>
+ As pets
+ </title>
+ <p id="70">
+ <ph id="244">
+ The Association of Zoos and Aquariums estimates that up to 12,000 tigers are being kept as private pets in the USA, significantly more than the world's entire wild population.
+ </ph>
+ <ph id="245">
+ 4,000 are believed to be in captivity in Texas alone.
+ </ph>
+ </p>
+ <p id="71">
+ <ph id="246">
+ In Brian De Palma's remake of Scarface, starring Al Pacino, Pacino's character, Tony Montana, aspires to obtaining all the exterior trappings of the American Dream, which in the character's opinion included keeping a pet tiger on his property.
+ </ph>
+ </p>
+ <p id="72">
+ <ph id="247">
+ Part of the reason for America's enormous tiger population relates to legislation.
+ </ph>
+ <ph id="248">
+ Only nineteen states have banned private ownership of tigers, fifteen require only a licence, and sixteen states have no regulations at all.
+ </ph>
+ </p>
+ <p id="73">
+ <ph id="249">
+ The success of breeding programmes at American zoos and circuses led to an overabundance of cubs in the 1980s and 90s, which drove down prices for the animals.
+ </ph>
+ <ph id="250">
+ The SPCA estimate there are now 500 lions, tigers and other big cats in private ownership just in the Houston area.
+ </ph>
+ </p>
+ <p id="74">
+ <ph id="251">
+ </ph>
+ </p>
+ </section>
+ <section id="23">
+ <title>
+ Cultural depictions
+ </title>
+ <p id="75">
+ <ph id="252">
+ The tiger replaces the lion as King of the Beasts in cultures of eastern Asia, representing royalty, fearlessness and wrath.
+ </ph>
+ <ph id="253">
+ Its forehead has a marking which resembles the Chinese character 王, which means "king"; consequently, many cartoon depictions of tigers in China and Korea are drawn with 王 on their forehead.
+ </ph>
+ </p>
+ <p id="76">
+ <ph id="254">
+ Of great importance in Chinese myth and culture, the tiger is one of the 12 Chinese zodiac animals.
+ </ph>
+ <ph id="255">
+ Also in various Chinese art and martial art, the tiger is depicted as an earth symbol and equal rival of the Chinese dragon- the two representing matter and spirit respectively.
+ </ph>
+ <ph id="256">
+ In fact, the Southern Chinese martial art Hung Ga is based on the movements of the Tiger and the Crane.
+ </ph>
+ <ph id="257">
+ In Imperial China, a tiger was the personification of war and often represented the highest army general (or present day defense secretary), while the emperor and empress were represented by a dragon and phoenix, respectively.
+ </ph>
+ <ph id="258">
+ The White Tiger (Chinese: 白虎; pinyin: Bái Hǔ) is one of the Four Symbols of the Chinese constellations.
+ </ph>
+ <ph id="259">
+ It is sometimes called the White Tiger of the West (西方白虎), and it represents the west and the autumn season.
+ </ph>
+ </p>
+ <p id="77">
+ <ph id="260">
+ In Buddhism, it is also one of the Three Senseless Creatures, symbolizing anger, with the monkey representing greed and the deer lovesickness.
+ </ph>
+ </p>
+ <p id="78">
+ <ph id="261">
+ The Tungusic people considered the Siberian tiger a near-deity and often referred to it as "Grandfather"
+ </ph>
+ <ph id="262">
+ or "Old man".
+ </ph>
+ <ph id="263">
+ The Udege and Nanai called it "Amba".
+ </ph>
+ <ph id="264">
+ The Manchu considered the Siberian tiger as Hu Lin, the king.
+ </ph>
+ </p>
+ <p id="79">
+ <ph id="265">
+ The widely worshiped Hindu goddess Durga, an aspect of Devi-Parvati, is a ten-armed warrior who rides the tigress (or lioness) Damon into battle.
+ </ph>
+ <ph id="266">
+ In southern India the god Aiyappa was associated with a tiger.
+ </ph>
+ </p>
+ <p id="80">
+ <ph id="267">
+ The weretiger replaces the werewolf in shapeshifting folklore in Asia; in India they were evil sorcerers while in Indonesia and Malaysia they were somewhat more benign.
+ </ph>
+ </p>
+ <p id="81">
+ <ph id="268">
+ The tiger continues to be a subject in literature; both Rudyard Kipling, in The Jungle Book, and William Blake, in Songs of Experience, depict the tiger as a menacing and fearful animal.
+ </ph>
+ <ph id="269">
+ In The Jungle Book, the tiger, Shere Khan, is the wicked mortal enemy of the protagonist, Mowgli.
+ </ph>
+ <ph id="270">
+ However, other depictions are more benign: Tigger, the tiger from A.
+ </ph>
+ <ph id="271">
+ A.
+ </ph>
+ <ph id="272">
+ Milne's Winnie-the-Pooh stories, is cuddly and likable.
+ </ph>
+ <ph id="273">
+ In the Man Booker Prize winning novel "Life of Pi,"
+ </ph>
+ <ph id="274">
+ the protagonist, Pi Patel, sole human survivor of a ship wreck in the Pacific Ocean, befriends another survivor: a large Bengal Tiger.
+ </ph>
+ <ph id="275">
+ The famous comic strip Calvin and Hobbes features Calvin and his stuffed tiger, Hobbes.
+ </ph>
+ <ph id="276">
+ A tiger is also featured on the cover of the popular cereal Frosted Flakes (also marketed as "Frosties") bearing the name "Tony the Tiger".
+ </ph>
+ </p>
+ <p id="82">
+ <ph id="277">
+ The Tiger is the national animal of Bangladesh, Nepal, India (Bengal Tiger) Malaysia (Malayan Tiger), North Korea and South Korea (Siberian Tiger).
+ </ph>
+ </p>
+ <p id="83">
+ <ph id="278">
+ </ph>
+ </p>
+ </section>
+ <section id="24">
+ <title>
+ World's favourite animal
+ </title>
+ <p id="84">
+ <ph id="279">
+ In a poll conducted by Animal Planet, the Tiger was voted the world's favourite animal, narrowly beating man's best friend, the dog.
+ </ph>
+ <ph id="280">
+ More than 50,000 viewers from 73 countries voted in the poll.
+ </ph>
+ <ph id="281">
+ The tiger received 21 percent of the vote, the dog 20, the dolphin 13, the horse 10, the lion 9, the snake 8, followed by the elephant, the chimpanzee, the orangutan and the whale.
+ </ph>
+ </p>
+ <p id="85">
+ <ph id="282">
+ Animal behaviourist Candy d'Sa, who worked with Animal Planet on the list, said: "We can relate to the tiger, as it is fierce and commanding on the outside, but noble and discerning on the inside".
+ </ph>
+ </p>
+ <p id="86">
+ <ph id="283">
+ Callum Rankine, international species officer at the World Wildlife Federation conservation charity, said the result gave him hope.
+ </ph>
+ <ph id="284">
+ "If people are voting tigers as their favourite animal, it means they recognise their importance, and hopefully the need to ensure their survival,"
+ </ph>
+ <ph id="285">
+ he said.
+ </ph>
+ </p>
+ <p id="87">
+ <ph id="286">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="9">
+ <title>
+ Gallery
+ </title>
+ <refbody>
+ <section id="25">
+ <table>
+ <tr>
+ <td>
+ <p>
+ Picture of Felis tigris (Panthera tigris) subspecies unknown
+ </p>
+ </td>
+ <td>
+ <p>
+ Dervish with a lion and a tiger. Mughal painting, c. 1650
+ </p>
+ </td>
+ <td>
+ <p>
+ Bengal tiger
+ </p>
+ </td>
+ <td>
+ <p>
+ Sumatran tiger
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>
+ Siberian Tiger
+ </p>
+ </td>
+ <td>
+ <p>
+ Siberian tiger
+ </p>
+ </td>
+ <td>
+ <p>
+ Bengal tiger cooling off at Bandhavghar, India
+ </p>
+ </td>
+ <td>
+ <p>
+ Vibrissae of a Tiger at Chester Zoo
+ </p>
+ </td>
+ </tr>
+ </table>
+ </section>
+ <p id="88">
+ <ph id="287">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="10">
+ <title>
+ See also
+ </title>
+ <refbody>
+ <section id="26">
+ <ul>
+ <li>
+ Black tiger (animal)
+ </li>
+ <li>
+ Maltese Tiger
+ </li>
+ <li>
+ Project Tiger, India
+ </li>
+ <li>
+ Siegfried &amp;amp; Roy, two famous tamers of tigers
+ </li>
+ <li>
+ Tiger Temple, a Buddhist temple in Thailand famous for its tame tigers
+ </li>
+ </ul>
+ </section>
+ <p id="89">
+ <ph id="288">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="11">
+ <title>
+ Cited references
+ </title>
+ <refbody>
+ <section id="27">
+ <ol>
+ <li id="cite_note-IUCN-0">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ Cat Specialist Group (2002). Panthera Tigris. 2006 IUCN Red List of Threatened Species. IUCN 2006. Retrieved on 10 May 2006. Database entry includes justification for why this species is endangered.
+ </li>
+ <li id="cite_note-1">
+ ^ Save The Tiger Fund | Wild Tiger Conservation
+ </li>
+ <li id="cite_note-britannica-2">
+ ^ "Encyclopaedia Britannica Online - Tiger (Panthera tigris)". Retrieved on 25 September, 2007.
+ </li>
+ <li id="cite_note-Lynx-3">
+ ^ Cat Specialist Group.
+ </li>
+ <li id="cite_note-bbc-4">
+ ^ "BBC Wildfacts – Tiger".
+ </li>
+ <li id="cite_note-Liddell-5">
+ ^ &amp;#160;
+ </li>
+ <li id="cite_note-6">
+ ^ Tiger at the Online Etymology Dictionary
+ </li>
+ <li id="cite_note-7">
+ ^ (Latin) &amp;#160;
+ </li>
+ <li id="cite_note-8">
+ ^ ""Panther"". Online Etymology Dictionary. Douglas Harper. Retrieved on 2007-07-05.
+ </li>
+ <li id="cite_note-9">
+ ^ ""WIKI Answers article on 'Group of tigers'"".
+ </li>
+ <li id="cite_note-10">
+ ^ Van den Hoek Ostende. 1999. Javan Tiger - Ruthlessly hunted down. 300 Pearls - Museum highlights of natural diversity. Downloaded on August 11, 2006.
+ </li>
+ <li id="cite_note-WWF-11">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ "WWF – Tigers – Ecology".
+ </li>
+ <li id="cite_note-der-tiger-12">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ <sup>
+ d
+ </sup>
+ <sup>
+ e
+ </sup>
+ <sup>
+ f
+ </sup>
+ (German) Vratislav Mazak: Der Tiger. Nachdruck der 3. Auflage von 1983. Westarp Wissenschaften Hohenwarsleben, 2004 ISBN 3 894327596
+ </li>
+ <li id="cite_note-13">
+ ^ Matthiessen, Peter. 2000. Tigers in the Snow, p. 47. The Harvill Press, London.
+ </li>
+ <li id="cite_note-Tigersnow-14">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ &amp;#160;
+ </li>
+ <li id="cite_note-15">
+ ^ Sunquist, Mel and Fiona Sunquist. 2002. Wild Cats of the World. University Of Chicago Press, Chicago
+ </li>
+ <li id="cite_note-16">
+ ^ Sunquist, Mel and Fiona Sunquist. 2002. Wild Cats of the World. University Of Chicago Press, Chicago
+ </li>
+ <li id="cite_note-17">
+ ^ Task force says tigers under siege
+ </li>
+ <li id="cite_note-18">
+ ^ &amp;#160;
+ </li>
+ <li id="cite_note-19">
+ ^ "No tigers found in Sariska: CBI". DeccanHerald.com. Retrieved on 2007-07-20. (Archive).
+ </li>
+ <li id="cite_note-20">
+ ^ "Laboratory of Genomic Diversity LGD".
+ </li>
+ <li id="cite_note-21">
+ ^ Cat Specialist Group (1996). Panthera tigris ssp. sumatrae. 2006 IUCN Red List of Threatened Species. IUCN 2006. Retrieved on 11 May 2006. Database entry includes a brief justification of why this subspecies is critically endangered and the criteria used.
+ </li>
+ <li id="cite_note-22">
+ ^ *Nowak, Ronald M. (1999) Walker's Mammals of the World. Johns Hopkins University Press. ISBN 0-8018-5789-9
+ </li>
+ <li id="cite_note-23">
+ ^ Cracraft J., Feinstein J., Vaughn J., Helm-Bychowski K. (1998) Sorting out tigers (Panthera tigris) Mitochondrial sequences, nuclear inserts, systematics, and conservation genetics. Animal Conservation 1: 139–150.
+ </li>
+ <li id="cite_note-24">
+ ^ Sunquist, Mel and Fiona Sunquist. 2002. Wild Cats of the World. University Of Chicago Press, Chicago
+ </li>
+ <li id="cite_note-25">
+ ^ Graham Batemann: Die Tiere unserer Welt Raubtiere, Deutsche Ausgabe: Bertelsmann Verlag, 1986.
+ </li>
+ <li id="cite_note-26">
+ ^ www.china.org.cn Retrieved on 6 October 2007
+ </li>
+ <li id="cite_note-xinhua-27">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ 绝迹24年华南虎重现陕西 村民冒险拍下照片
+ </li>
+ <li id="cite_note-28">
+ ^ BBC NEWS | World | Asia-Pacific | Rare China tiger seen in the wild
+ </li>
+ <li id="cite_note-29">
+ ^ Bambang M. 2002. In search of 'extinct' Javan tiger. The Jakarta Post (October 30).
+ </li>
+ <li id="cite_note-30">
+ ^ Harimau jawa belum punah! (Indonesian Javan Tiger website)
+ </li>
+ <li id="cite_note-casp-31">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ "The Caspian Tiger - Panthera tigris virgata". Retrieved on 12 October, 2007.
+ </li>
+ <li id="cite_note-casp2-32">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ "The Caspian Tiger at www.lairweb.org.nz". Retrieved on 12 October, 2007.
+ </li>
+ <li id="cite_note-hybridisation-33">
+ ^ "History of big cat hybridisation". Retrieved on 28 September, 2007.
+ </li>
+ <li id="cite_note-34">
+ ^ &amp;#160;
+ </li>
+ <li id="cite_note-liger-35">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ &amp;#160;
+ </li>
+ <li id="cite_note-36">
+ ^ "tigon - Encyclopædia Britannica Article". Retrieved on 12 September, 2007.
+ </li>
+ <li id="cite_note-nz-37">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ "White tigers". Retrieved on 25 September, 2007.
+ </li>
+ <li id="cite_note-38">
+ ^ The white tiger today and the unusual white lion, [1]
+ </li>
+ <li id="cite_note-39">
+ ^ White Tigers, [2]
+ </li>
+ <li id="cite_note-40">
+ ^ "White Tiger Facts". Retrieved on 26 September, 2007.
+ </li>
+ <li id="cite_note-41">
+ ^ White Tigers, [3]
+ </li>
+ <li id="cite_note-42">
+ ^ Snow Tigers, [4]
+ </li>
+ <li id="cite_note-43">
+ ^ The white tiger today and the unusual white lion, [5]
+ </li>
+ <li id="cite_note-44">
+ ^ [6]
+ </li>
+ <li id="cite_note-zoogoer-45">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ "Zoogoer - Tiger, Panthera tigris". Retrieved on 5 October, 2007.
+ </li>
+ <li id="cite_note-46">
+ ^ Karanth, K.U., Nichols, J.D., Seidensticker, J., Dinerstein, E., Smith, J.L.D., McDougal, C., Johnsingh, A.J.T., Chundawat, R.S. (2003) Science deficiency in conservation practice: the monitoring of tiger populations in India. Animal Conservation (61): 141-146 Full text
+ </li>
+ <li id="cite_note-Haemig-47">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ "Sympatric Tiger and Leopard: How two big cats coexist in the same area". Ecology.info
+ </li>
+ <li id="cite_note-Perry-48">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ <sup>
+ d
+ </sup>
+ &amp;#160;
+ </li>
+ <li id="cite_note-49">
+ ^ Man-eaters. The tiger and lion, attacks on humans
+ </li>
+ <li id="cite_note-50">
+ ^ ADW:Panthera tigris: Information, http://animaldiversity.ummz.umich.edu/site/accounts/information/Panthera_tigris.html
+ </li>
+ <li id="cite_note-51">
+ ^ ADW:Panthera tigris: Information, http://animaldiversity.ummz.umich.edu/site/accounts/information/Panthera_tigris.html
+ </li>
+ <li id="cite_note-52">
+ ^ Schaller. G The Deer and the Tiger: A Study of Wildlife in India 1984, University Of Chicago Press
+ </li>
+ <li id="cite_note-53">
+ ^ Sankhala 1997, p.&amp;#160;17.
+ </li>
+ <li id="cite_note-54">
+ ^ Sankhala 1997, p.&amp;#160;23.
+ </li>
+ <li id="cite_note-DHOLE-55">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ &amp;#160;
+ </li>
+ <li id="cite_note-56">
+ ^ Tiger – BangaliNET.com
+ </li>
+ <li id="cite_note-57">
+ ^ Tiger – Oakland Zoo
+ </li>
+ <li id="cite_note-58">
+ ^ Sunquist, Fiona &amp;amp; Mel Sunquist. 1988. Tiger Moon. The University of Chicago Press, Chicago.
+ </li>
+ <li id="cite_note-59">
+ ^
+ </li>
+ <li id="cite_note-IUCN-Reuters-60">
+ ^ "The IUCN-Reuters Media Awards 2000". IUCN. Retrieved on 2007-08-17.
+ </li>
+ <li id="cite_note-savethetiger-61">
+ ^ "Amur Tiger". Save The Tiger Fund. Retrieved on 2007-08-17.
+ </li>
+ <li id="cite_note-62">
+ ^ Big Cat Recuse - Tiger
+ </li>
+ <li id="cite_note-Over_half_of_tigers_lost_in_5_years:_census-63">
+ ^ [7].
+ </li>
+ <li id="cite_note-64">
+ ^ Simon Denyer (March 6, 2006). "Dalai Lama offers Indian tigers a lifeline". iol.co.za. Retrieved on 2007-07-20.
+ </li>
+ <li id="cite_note-65">
+ ^ Justin Huggler (February 18, 2006). "Fur flies over tiger plight". New Zealand Herald. Tibet.com. Retrieved on 2007-07-20.
+ </li>
+ <li id="cite_note-66">
+ ^ "Dalai Lama campaigns for wildlife". BBC News (April 6, 2005). Retrieved on 2007-07-20.
+ </li>
+ <li id="cite_note-67">
+ ^ Indian tiger isn't 100 per cent “swadeshi (Made in India)”; by Pallava Bagla; Indian Express Newspaper; November 19, 1998
+ </li>
+ <li id="cite_note-68">
+ ^ Tainted Royalty, Wildlife: Royal Bengal Tiger, a controversy arises over the purity of the Indian tiger after DNA samples show Siberian tiger genes. By Subhadra Menon. India Today, November 17, 1997
+ </li>
+ <li id="cite_note-69">
+ ^ The Tale of Tara, 4: Tara's Heritage from Tiger Territory website
+ </li>
+ <li id="cite_note-70">
+ ^ Genetic pollution in wild Bengal tigers, Tiger Territory website
+ </li>
+ <li id="cite_note-71">
+ ^ Interview with Billy Arjan Singh: Dudhwa's Tiger man, October 2000, Sanctuary Asia Magazine, sanctuaryasia.com
+ </li>
+ <li id="cite_note-72">
+ ^ Mitochondrial DNA sequence divergence among big cats and their hybrids by Pattabhiraman Shankaranarayanan* and Lalji Singh*, *Centre for Cellular and Molecular Biology, Uppal Road, Hyderabad 500 007, India, Centre for DNA Fingerprinting and Diagnostics, CCMB Campus, Uppal Road, Hyderabad 500 007, India
+ </li>
+ <li id="cite_note-73">
+ ^ Central Zoo Authority of India (CZA), Government of India
+ </li>
+ <li id="cite_note-74">
+ ^ "Indians Look At Their Big Cats' Genes", Science, Random Samples, Volume 278, Number 5339, Issue of 31 October 1997, 278: 807 (DOI: 10.1126/science.278.5339.807b) (in Random Samples),The American Association for the Advancement of Science
+ </li>
+ <li id="cite_note-75">
+ ^ BOOKS By &amp;amp; About Billy Arjan Singh
+ </li>
+ <li id="cite_note-76">
+ ^ Book - Tara&amp;#160;: The Cocktail Tigress/Ram Lakhan Singh. Edited by Rahul Karmakar. Allahabad, Print World, 2000, xxxviii, 108 p., ills., $22. ISBN 81-7738-000-1. A book criticizing Billy Arjan Singh's release of hand reared hybrid Tigress Tara in the wild at Dudhwa National Park in India
+ </li>
+ <li id="cite_note-77">
+ ^ FAQs | Save China's Tigers
+ </li>
+ <li id="cite_note-78">
+ ^ Xinhua - English
+ </li>
+ <li id="cite_note-79">
+ ^ FAQs | Save China's Tigers
+ </li>
+ <li id="cite_note-Tiger-hunting-80">
+ ^ vide Royal Tiger (nom-de-plume) in The Manpoora Tiger - about a Tiger Hunt in Rajpootanah. (1836) Bengal Sporting Magazine, Vol IV. reproduced in The Treasures of Indian Wildlife
+ </li>
+ <li id="cite_note-81">
+ ^ Man-eaters. The tiger and lion, attacks on humans
+ </li>
+ <li id="cite_note-82">
+ ^ Man-eaters. The tiger and lion, attacks on humans
+ </li>
+ <li id="cite_note-83">
+ ^ Increasing tiger attacks trigger panic around Tadoba-Andhari reserve
+ </li>
+ <li id="cite_note-84">
+ ^ BBC NEWS | Programmes | From Our Own Correspondent | Beijing's penis emporium
+ </li>
+ <li id="cite_note-85">
+ ^ WWF: Chinese tiger farms must be investigated
+ </li>
+ <li id="cite_note-86">
+ ^ WWF: Breeding tigers for trade soundly rejected at cites
+ </li>
+ <li id="cite_note-book-of-general-ignorance-87">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ <sup>
+ d
+ </sup>
+ <sup>
+ e
+ </sup>
+ Lloyd, J &amp;amp; Mitchinson, J: "The Book of General Ignorance". Faber &amp;amp; Faber, 2006.
+ </li>
+ <li id="cite_note-88">
+ ^ Tiger Culture | Save China's Tigers
+ </li>
+ <li id="cite_note-Cooper92-89">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ <sup>
+ d
+ </sup>
+ &amp;#160;
+ </li>
+ <li id="cite_note-90">
+ ^ Balambal, V (1997). "19. Religion - Identity - Human Values - Indian Context". Bioethics in India: Proceedings of the International Bioethics Workshop in Madras: Biomanagement of Biogeoresources, 16-19 Jan. 1997. Eubios Ethics Institute. Retrieved on 2007-10-08.
+ </li>
+ <li id="cite_note-summers66-91">
+ ^ &amp;#160;
+ </li>
+ <li id="cite_note-javaweretigerstuff-92">
+ ^ &amp;#160;
+ </li>
+ <li id="cite_note-93">
+ ^ National Animal Panthera tigris, Tiger is the national animal of India Govt. of India website,
+ </li>
+ <li id="cite_note-94">
+ ^ "National Symbols of India". High Commission of India, London. Retrieved on 2007-10-25.
+ </li>
+ <li id="cite_note-int.iol.co.za-95">
+ ^
+ <sup>
+ a
+ </sup>
+ <sup>
+ b
+ </sup>
+ <sup>
+ c
+ </sup>
+ Tiger tops dog as world's favourite animal
+ </li>
+ <li id="cite_note-96">
+ ^ Pers® - The Tiger is the World's Favorite Animal
+ </li>
+ <li id="cite_note-97">
+ ^ CBBC Newsround | Animals | Tiger 'is our favourite animal'
+ </li>
+ <li id="cite_note-98">
+ ^ Endangered tiger earns its stripes as the world's most popular beast | Independent, The (London) | Find Articles at BNET.com
+ </li>
+ </ol>
+ </section>
+ <p id="90">
+ <ph id="289">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="12">
+ <title>
+ References
+ </title>
+ <refbody>
+ <section id="28">
+ <ul>
+ <li>
+ Brakefield, T. (1993). , Voyageur press.
+ </li>
+ <li>
+ Dr. Tony Hare. (2001) Animal Habitats P. 172 ISBN 0-8160-4594-1
+ </li>
+ <li>
+ Kothari, Ashok S. &amp;amp; Chhapgar, Boman F. (eds). 2005. The Treasures of Indian Wildlife. Bombay Natural History Society and Oxford University Press, Mumbai.
+ </li>
+ <li>
+ Mazák, V. (1981). Panthera tigris. (PDF). Mammalian Species, 152: 1-8. American Society of Mammalogists.
+ </li>
+ <li>
+ Nowak, Ronald M. (1999) Walker's Mammals of the World. Johns Hopkins University Press. ISBN 0-8018-5789-9
+ </li>
+ <li>
+ Abridged German translation of Return of the Tiger, Lustre Press, 1993.
+ </li>
+ <li>
+ Seidensticker, John. (1999) Riding the Tiger. Tiger Conservation in Human-dominated Landscapes Cambridge University Press. ISBN 0521648351
+ </li>
+ </ul>
+ </section>
+ <p id="91">
+ <ph id="290">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="13">
+ <title>
+ External links
+ </title>
+ <refbody>
+ <section id="29">
+ <ul>
+ <li>
+ 21st Century Tiger: information about tigers and conservation projects
+ </li>
+ <li>
+ Save China's Tigers: information about tigers and the South China Tiger rewilding project in Africa
+ </li>
+ <li>
+ Save The Tiger Fund
+ </li>
+ <li>
+ Sundarbans Tiger Project: research and conservation of tigers in the largest remaining mangrove forest in the world
+ </li>
+ <li>
+ Tiger Canyons Homepage: information about tigers and the Crossbred Tiger Rewilding project
+ </li>
+ <li>
+ Tigers in Crisis
+ </li>
+ <li>
+ WWF – Tigers
+ </li>
+ </ul>
+ </section>
+ <p id="92">
+ <ph id="291">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="imagelist">
+ <refbody>
+ <image href="#DEMOLIBRARY#/images/250px-Tigerramki.jpg">
+ <alt>
+ A Bengal Tiger (P. tigris tigris) in India's Bandhavgarh reserve.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Status_iucn2.3_EN.svg.png">
+ <alt>
+ 180px-Status_iucn2.3_EN.svg.png
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Tiger_map.jpg">
+ <alt>
+ Historical distribution of tigers (pale yellow) and 2006 (green).
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/220px-Tiger_distribution3.PNG">
+ <alt>
+ Range of the tiger including the western part 1900 and 1990
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Siberian_Tiger_sf.jpg">
+ <alt>
+ Siberian tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/230px-TigerSkelLyd1.png">
+ <alt>
+ Skeleton
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Tiger_Bandavgarh_adjusted_levels.jpg">
+ <alt>
+ Bengal tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Tiger_032.jpg">
+ <alt>
+ Indochinese tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Tiger_in_the_water.jpg">
+ <alt>
+ Malayan tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Panthera_tigris_sumatran_subspecies.jpg">
+ <alt>
+ Sumatran tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Tiger_in_the_snow_at_the_Detroit_Zoo_March_2008_pic_2.jpg">
+ <alt>
+ Siberian Tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Panthera_tigris_amoyensis.jpg">
+ <alt>
+ South China tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Panthera_tigris_balica.jpg">
+ <alt>
+ A hunted down Balinese tiger.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Panthera_tigris_sondaica_01.jpg">
+ <alt>
+ A photograph of a Javan tiger.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Panthera_tigris_virgata.jpg">
+ <alt>
+ Caspian tiger
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Bertramliger.jpg">
+ <alt>
+ A liger is the offspring of a male lion and female tiger.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/230px-Singapore_Zoo_Tigers.jpg">
+ <alt>
+ A pair of white tigers at the Singapore Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/230px-Golden_tiger_1_-_Buffalo_Zoo.jpg">
+ <alt>
+ A rare strawberry tiger at Buffalo Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/230px-037tiger.jpg">
+ <alt>
+ Tiger dentition. The large canines are used to make the killing bite, but they tear meat when feeding using the carnassial teeth
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/240px-Stud_327_with_Blesbuck.jpg">
+ <alt>
+ A South China tiger of the Save China's Tigers project with his blesbuck kill
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Tigergebiss.jpg">
+ <alt>
+ Tigers' extremely strong jaws and sharp teeth make them superb predators.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-1990tiger.PNG">
+ <alt>
+ Tiger headcount in 1990
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/240px-ElephantbackTigerHunt.jpg">
+ <alt>
+ Tiger hunting on elephant-back, India, early 19th Century
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Tigress-Jowlagiri.jpg">
+ <alt>
+ The Tigress of Jowlagiri, responsible for the deaths of 15 people, killed by Kenneth Anderson
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/240px-TigerSkinning.jpg">
+ <alt>
+ Instructions for tiger skinning
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Kuniyoshi_Utagawa%2C_Tiger.jpg">
+ <alt>
+ 19th century painting of a tiger by Kuniyoshi Utagawa
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Tipu_Sultan%27s_Tiger.JPG">
+ <alt>
+ A toy showing a tiger pouncing on a redcoat (British soldier). This belonged to Tippu Sultan who was popularly known as the Tiger of Mysore.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/84px-Brehms_Het_Leven_der_Dieren_Zoogdieren_Orde_4_Tijger_%28Felis_tigris%29.jpg">
+ <alt>
+ 84px-Brehms_Het_Leven_der_Dieren_Zoogdieren_Orde_4_Tijger_%28Felis_tigris%29.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/83px-Indischer_Maler_um_1650_%28II%29_001.jpg">
+ <alt>
+ 83px-Indischer_Maler_um_1650_%28II%29_001.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/80px-India_tiger.jpg">
+ <alt>
+ 80px-India_tiger.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/97px-Sumatratiger-004.jpg">
+ <alt>
+ 97px-Sumatratiger-004.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/120px-Siberischer_tiger_de_edit02.jpg">
+ <alt>
+ 120px-Siberischer_tiger_de_edit02.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/120px-Siberian-Tiger.jpg">
+ <alt>
+ 120px-Siberian-Tiger.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/120px-Tiger_cooling_off_at_Bandhavghar.jpg">
+ <alt>
+ 120px-Tiger_cooling_off_at_Bandhavghar.jpg
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/120px-Vibrissae_of_a_Tiger_at_Chester_Zoo.jpg">
+ <alt>
+ 120px-Vibrissae_of_a_Tiger_at_Chester_Zoo.jpg
+ </alt>
+ </image>
+ </refbody>
+ </reference>
+</reference> \ No newline at end of file
diff --git a/Processing/demolibrary/zebra-wikipedia.dita b/Processing/demolibrary/zebra-wikipedia.dita
new file mode 100644
index 0000000..d9af33c
--- /dev/null
+++ b/Processing/demolibrary/zebra-wikipedia.dita
@@ -0,0 +1,884 @@
+<?xml version='1.0' encoding='utf-8'?>
+<reference>
+ <title>
+ Zebra
+ </title>
+ <shortdesc>
+ <ph id="2">
+ Zebras are odd-toed ungulates of the Equidae family native to eastern, southern and southwestern Africa.
+ </ph>
+ <ph id="3">
+ They are best known for their distinctive white and black stripes, which come in different patterns unique to each individual.
+ </ph>
+ <ph id="4">
+ They are generally social animals and can be seen in small harems to large herds.
+ </ph>
+ </shortdesc>
+ <prolog>
+ <source href="http://en.wikipedia.org/w/index.php?oldid=235155356">
+ <publisher>
+ wikipedia.org
+ </publisher>
+ <critdates>
+ <created date="2008-09-05">
+ <revised modified="2008-09-05">
+ </revised>
+ </created>
+ </critdates>
+ </source>
+ </prolog>
+ <refbody>
+ <section id="infobox">
+ <title>
+ Scientific classification
+ </title>
+ <properties>
+ <property>
+ <proptype>
+ Kingdom
+ </proptype>
+ <propvalue>
+ Animalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Phylum
+ </proptype>
+ <propvalue>
+ Chordata
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Class
+ </proptype>
+ <propvalue>
+ Mammalia
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Order
+ </proptype>
+ <propvalue>
+ Perissodactyla
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Family
+ </proptype>
+ <propvalue>
+ Equidae
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Genus
+ </proptype>
+ <propvalue>
+ Equus
+ </propvalue>
+ </property>
+ <property>
+ <proptype>
+ Subgenus
+ </proptype>
+ <propvalue>
+ Hippotigris
+Dolichohippus
+ </propvalue>
+ </property>
+ </properties>
+ </section>
+ <p id="2">
+ <ph id="5">
+ Zebras are generally 2.3 m (8ft) long, stand 1.25-1.5 m (4-5ft) at the shoulder, and weigh around 300kg (660 lbs), although some can grow to more than 410 kg (900 lbs).
+ </ph>
+ <ph id="6">
+ In addition to their stripes, zebras have erect, mohawk-like manes.
+ </ph>
+ <ph id="7">
+ Unlike their closest relatives, horses and donkeys, zebras have not been truly domesticated.
+ </ph>
+ <ph id="8">
+ There are three species of zebra: the Plains Zebra, Grevy's Zebra and the Mountain Zebra.
+ </ph>
+ <ph id="9">
+ They can be found in a variety of habitats, such as grasslands, savannas, woodlands, thorny scrublands, mountains and coastal hills.
+ </ph>
+ </p>
+ <p id="3">
+ <ph id="10">
+ The name "zebra"
+ </ph>
+ <ph id="11">
+ comes from the Old Portuguese word zevra which means "wild ass".
+ </ph>
+ <ph id="12">
+ The pronunciation (in IPA) is /ˈzɛbrə/ (ZEB-ra) internationally, or /ˈziːbrə/ (ZEE-bra) in North America.
+ </ph>
+ </p>
+ <p id="4">
+ <ph id="13">
+ </ph>
+ </p>
+ </refbody>
+ <reference id="2">
+ <title>
+ Taxonomy and evolution
+ </title>
+ <refbody>
+ <p id="5">
+ <ph id="14">
+ Zebras were the second species to diverge from the earliest proto-horses, after the asses, around 4 million years ago.
+ </ph>
+ <ph id="15">
+ The Grevy's zebra is believed to have been the first zebra species to emerge.
+ </ph>
+ <ph id="16">
+ Fossils of an ancient equid were discovered in the Hagerman Fossil Beds National Monument in Hagerman, Idaho.
+ </ph>
+ <ph id="17">
+ It was named the Hagerman horse with a scientific name of Equus simplicidens.
+ </ph>
+ <ph id="18">
+ It is believed to have been similar to the Grevy's zebra.
+ </ph>
+ <ph id="19">
+ The animals had stocky zebra-like bodies and short, narrow, donkey-like skulls.
+ </ph>
+ <ph id="20">
+ The Grevy's zebra also has a donkey-like skull.
+ </ph>
+ <ph id="21">
+ The Hagerman horse is also called the American zebra or Hagerman zebra.
+ </ph>
+ </p>
+ <p id="6">
+ <ph id="22">
+ </ph>
+ </p>
+ <section id="2">
+ <title>
+ Species
+ </title>
+ <p id="7">
+ <ph id="23">
+ There are three extant species, as well as several subspecies.
+ </ph>
+ <ph id="24">
+ Zebra populations vary a great deal, and the relationships between and the taxonomic status of several of the subspecies are well known.
+ </ph>
+ </p>
+ <p id="8">
+ <ph id="25">
+ The Plains Zebra (Equus quagga, formerly Equus burchelli) is the most common, and has or had about twelve subspecies distributed across much of southern and eastern Africa.
+ </ph>
+ <ph id="26">
+ It, or particular subspecies of it, have also been known as the Common Zebra, the Dauw, Burchell's Zebra (actually the subspecies Equus quagga burchelli), Chapman's Zebra, Wahlberg's Zebra, Selous' Zebra, Grant's Zebra, Boehm's Zebra and the Quagga (another extinct subspecies, Equus quagga quagga).
+ </ph>
+ </p>
+ <p id="9">
+ <ph id="27">
+ The Mountain Zebra (Equus zebra) of southwest Africa tends to have a sleek coat with a white belly and narrower stripes than the Plains Zebra.
+ </ph>
+ <ph id="28">
+ It has two subspecies and is classified as endangered.
+ </ph>
+ </p>
+ <p id="10">
+ <ph id="29">
+ Grevy's Zebra (Equus grevyi) is the largest type, with a long, narrow head making it appear rather mule-like.
+ </ph>
+ <ph id="30">
+ It is an inhabitant of the semi-arid grasslands of Ethiopia and northern Kenya.
+ </ph>
+ <ph id="31">
+ The Grevy's Zebra is one of the rarest species of zebra around today, and is classified as endangered.
+ </ph>
+ </p>
+ <p id="11">
+ <ph id="32">
+ Although zebra species may have overlapping ranges, they do not interbreed.
+ </ph>
+ <ph id="33">
+ This held true even when the Quagga and Burchell's race of Plains Zebra shared the same area.
+ </ph>
+ <ph id="34">
+ According to Dorcas McClintock in "A Natural History Of Zebras,"
+ </ph>
+ <ph id="35">
+ Grevy's zebra has 46 chromosomes; plains zebras have 44 chromosomes and mountain zebras have 32 chromosomes.
+ </ph>
+ <ph id="36">
+ In captivity, Plains Zebras have been crossed with mountain zebras.
+ </ph>
+ <ph id="37">
+ The hybrid foals lacked a dewlap and resembled the Plains Zebra apart from their larger ears and their hindquarters pattern.
+ </ph>
+ <ph id="38">
+ Attempts to breed a Grevy's zebra stallion to Mountain Zebra mares resulted in a high rate of miscarriage.
+ </ph>
+ </p>
+ <p id="12">
+ <ph id="39">
+ </ph>
+ </p>
+ </section>
+ <section id="3">
+ <title>
+ Species classification
+ </title>
+ <ul>
+ <li>
+ Genus: Equus
+ </li>
+ </ul>
+ <ul>
+ <li>
+ Subgenus: Hippotigris
+ </li>
+ </ul>
+ <ul>
+ <li>
+ Plains Zebra, Equus quagga
+ </li>
+ </ul>
+ <ul>
+ <li>
+ Quagga, Equus quagga quagga (extinct)
+ </li>
+ <li>
+ Burchell's Zebra, Equus quagga burchellii (includes Damara Zebra)
+ </li>
+ <li>
+ Grant's Zebra, Equus quagga boehmi
+ </li>
+ <li>
+ Selous' zebra, Equus quagga borensis
+ </li>
+ <li>
+ Chapman's Zebra, Equus quagga chapmani
+ </li>
+ <li>
+ Crawshay's Zebra, Equus quagga crawshayi
+ </li>
+ </ul>
+ <li>
+ Mountain Zebra, Equus zebra
+ <ul>
+ </ul>
+ </li>
+ <li>
+ Cape Mountain Zebra, Equus zebra zebra
+ </li>
+ <li>
+ Hartmann's Mountain Zebra, Equus zebra hartmannae
+ </li>
+ <li>
+ Subgenus: Dolichohippus
+ <ul>
+ </ul>
+ </li>
+ <li>
+ Grevy's Zebra, Equus grevyi
+ </li>
+ <p id="13">
+ <ph id="40">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="3">
+ <title>
+ Physical attributes
+ </title>
+ <refbody>
+ <p id="14">
+ <ph id="41">
+ </ph>
+ </p>
+ <section id="4">
+ <title>
+ Stripes
+ </title>
+ <p id="15">
+ <ph id="42">
+ Zebras are black or dark animals with white stripes and their bellies have a large white blotch for camouflage purposes.
+ </ph>
+ <ph id="43">
+ Some zebras have brown "shadow stripes"
+ </ph>
+ <ph id="44">
+ in between the white and black coloring.
+ </ph>
+ </p>
+ <p id="16">
+ <ph id="45">
+ Zebras are described as black with white stripes rather than the reverse for the following three reasons:
+ </ph>
+ </p>
+ <ol>
+ <li>
+ White equids would not survive well in the African plains or forests.
+ </li>
+ <li>
+ The quagga, an extinct Plains zebra subspecies, had the zebra striping pattern in the front of the animal, but had a dark rump.
+ </li>
+ <li>
+ When the region between the pigmented bands becomes too wide, secondary stripes emerge, as if suppression was weakening.
+ </li>
+ </ol>
+ <p id="17">
+ <ph id="46">
+ The fact that some zebras have pure white bellies and legs is not very strong evidence for a white background, since many animals of different colors have white or light colored bellies and legs.
+ </ph>
+ </p>
+ <p id="18">
+ <ph id="47">
+ The stripes are typically vertical on the head, neck, forequarters, and main body, with horizontal stripes at the rear and on the legs of the animal.
+ </ph>
+ <ph id="48">
+ The "zebra crossing"
+ </ph>
+ <ph id="49">
+ is named after the zebra's black and white stripes.
+ </ph>
+ </p>
+ <p id="19">
+ <ph id="50">
+ Some zoologists believe that the stripes act as a camouflage mechanism.
+ </ph>
+ <ph id="51">
+ This is accomplished in several ways.
+ </ph>
+ <ph id="52">
+ First, the vertical striping helps the zebra hide in grass.
+ </ph>
+ <ph id="53">
+ While seeming absurd at first glance considering that grass is neither white nor black, it is supposed to be effective against the zebra's main predator, the lion, which is color blind.
+ </ph>
+ <ph id="54">
+ Theoretically a zebra standing still in tall grass may not be noticed at all by a lion.
+ </ph>
+ <ph id="55">
+ Additionally, since zebras are herd animals, the stripes may help to confuse predators - a number of zebras standing or moving close together may appear as one large animal, making it more difficult for the lion to pick out any single zebra to attack.
+ </ph>
+ <ph id="56">
+ A herd of zebras scattering to avoid a predator will also represent to that predator a confused mass of vertical stripes travelling in multiple directions making it difficult for the predator to track an individual visually as it separates from its herdmates, although biologists have never observed lions appearing confused by zebra stripes.
+ </ph>
+ </p>
+ <p id="20">
+ <ph id="57">
+ Stripes are also believed to play a role in sexual attractions, with slight variations of the pattern allowing the animals to distinguish between individuals.
+ </ph>
+ </p>
+ <p id="21">
+ <ph id="58">
+ A more recent theory, supported by experiment, posits that the disruptive colouration is also an effective means of confusing the visual system of the blood-sucking tsetse fly.
+ </ph>
+ <ph id="59">
+ Alternative theories include that the stripes coincide with fat patterning beneath the skin, serving as a thermoregulatory mechanism for the zebra, and that wounds sustained disrupt the striping pattern to clearly indicate the fitness of the animal to potential mates.
+ </ph>
+ </p>
+ <p id="22">
+ <ph id="60">
+ </ph>
+ </p>
+ </section>
+ <section id="5">
+ <title>
+ Gaits
+ </title>
+ <p id="23">
+ <ph id="61">
+ Like horses, zebras walk, trot, canter and gallop.
+ </ph>
+ <ph id="62">
+ They are generally slower than horses but their great stamina helps them outpace predators.
+ </ph>
+ <ph id="63">
+ When chased, a zebra will zig-zag from side to side making it more difficult for the predator.
+ </ph>
+ <ph id="64">
+ When cornered the zebra will rear up and kick or bite its attacker.
+ </ph>
+ </p>
+ <p id="24">
+ <ph id="65">
+ </ph>
+ </p>
+ </section>
+ <section id="6">
+ <title>
+ Senses
+ </title>
+ <p id="25">
+ <ph id="66">
+ Zebras have excellent eyesight.
+ </ph>
+ <ph id="67">
+ It is believed that they can see in color.
+ </ph>
+ <ph id="68">
+ Like most ungulates the zebra has its eyes on the sides of its head, giving it a wide field of view.
+ </ph>
+ <ph id="69">
+ Zebras also have night vision, although not as advanced as that of most of their predators, but their hearing compensates.
+ </ph>
+ </p>
+ <p id="26">
+ <ph id="70">
+ Zebras have great hearing, and tend to have larger, rounder ears than horses.
+ </ph>
+ <ph id="71">
+ Like horses and other ungulates, zebra can turn their ears in almost any direction.
+ </ph>
+ <ph id="72">
+ In addition to eyesight and hearing, zebras have an acute sense of smell and taste.
+ </ph>
+ </p>
+ <p id="27">
+ <ph id="73">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="4">
+ <title>
+ Ecology and behavior
+ </title>
+ <refbody>
+ <p id="28">
+ <ph id="74">
+ </ph>
+ </p>
+ <section id="7">
+ <title>
+ Harems
+ </title>
+ <p id="29">
+ <ph id="75">
+ Like most members of the horse family, zebras are highly sociable.
+ </ph>
+ <ph id="76">
+ Their social structure, however, depends on the species.
+ </ph>
+ <ph id="77">
+ Mountain zebras and Plains zebras live in groups, known as 'harems', consisting of one stallion with up to six mares and their foals.
+ </ph>
+ <ph id="78">
+ Bachelor males either live alone or with groups of other bachelors until they are old enough to challenge a breeding stallion.
+ </ph>
+ <ph id="79">
+ When attacked by packs of hyenas or wild dogs, a zebra group will huddle together with the foals in the middle while the stallion tries to ward them off.
+ </ph>
+ </p>
+ <p id="30">
+ <ph id="80">
+ Unlike the other zebra species, Grevy's zebras do not have permanent social bonds.
+ </ph>
+ <ph id="81">
+ A group of these zebras rarely stays together for more than a few months.
+ </ph>
+ <ph id="82">
+ The foals stay with their mother, while the adult male lives alone.
+ </ph>
+ <ph id="83">
+ However like the other two zebra species, bachelor male zebras will organize in groups.
+ </ph>
+ </p>
+ <p id="31">
+ <ph id="84">
+ Like horses, zebras sleep standing up and only sleep when neighbors are around to warn them of predators.
+ </ph>
+ </p>
+ <p id="32">
+ <ph id="85">
+ </ph>
+ </p>
+ </section>
+ <section id="8">
+ <title>
+ Communication
+ </title>
+ <p id="33">
+ <ph id="86">
+ Zebras communicate with each other with high pitched barks and whinnying.
+ </ph>
+ <ph id="87">
+ Grevy's zebras make mule-like brays.
+ </ph>
+ <ph id="88">
+ A zebra’s ears signify its mood.
+ </ph>
+ <ph id="89">
+ When a zebra is in a calm, tense or friendly mood, its ears stand erect.
+ </ph>
+ <ph id="90">
+ When it is frightened, its ears are pushed forward.
+ </ph>
+ <ph id="91">
+ When angry, the ears are pulled backward.
+ </ph>
+ <ph id="92">
+ When surveying an area for predators, zebras will stand in an alert posture; with ears erect, head held high, and staring.
+ </ph>
+ <ph id="93">
+ When tense they will also snort.
+ </ph>
+ <ph id="94">
+ When a predator is spotted or sensed, a zebra will bark (or bray) loudly.
+ </ph>
+ </p>
+ <p id="34">
+ <ph id="95">
+ </ph>
+ </p>
+ </section>
+ <section id="9">
+ <title>
+ Food and foraging
+ </title>
+ <p id="35">
+ <ph id="96">
+ Zebras are very adaptable grazers.
+ </ph>
+ <ph id="97">
+ They feed mainly on grasses but will also eat shrubs, herbs, twigs, leaves and bark.
+ </ph>
+ <ph id="98">
+ Their well adapted digestive system allows them to subsist on diets of lower nutritional quality than that necessary for herbivores.
+ </ph>
+ </p>
+ <p id="36">
+ <ph id="99">
+ </ph>
+ </p>
+ </section>
+ <section id="10">
+ <title>
+ Reproduction
+ </title>
+ <p id="37">
+ <ph id="100">
+ Like most animal species, female zebras mature earlier than the males and a mare may have her first foal by the age of three.
+ </ph>
+ <ph id="101">
+ Males are not able to breed until the age of five or six.
+ </ph>
+ <ph id="102">
+ Mares may give birth to one foal every twelve months.
+ </ph>
+ <ph id="103">
+ She nurses the foal for up to a year.
+ </ph>
+ <ph id="104">
+ Like horses, zebras are able to stand, walk and suckle shortly after they're born.
+ </ph>
+ <ph id="105">
+ A zebra foal is brown and white instead of black and white at birth.
+ </ph>
+ </p>
+ <p id="38">
+ <ph id="106">
+ Plains and Mountain zebra foals are protected by their mother as well as the head stallion and the other mares in their group.
+ </ph>
+ <ph id="107">
+ Grevy’s zebra foals have only their mother as a regular protector since, as noted above, Grevy's zebra groups often disband after a few months.
+ </ph>
+ </p>
+ <p id="39">
+ <ph id="108">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="5">
+ <title>
+ Human interactions
+ </title>
+ <refbody>
+ <p id="40">
+ <ph id="109">
+ The fourth Mughal emperor Jahangir (r.1605-27), commissioned a painting of the zebra.
+ </ph>
+ <ph id="110">
+ In this painting executed by Ustad Mansur, the zebra is shown with stirrups.
+ </ph>
+ </p>
+ <p id="41">
+ <ph id="111">
+ </ph>
+ </p>
+ <section id="11">
+ <title>
+ Domestication
+ </title>
+ <p id="42">
+ <ph id="112">
+ Attempts have been made to train zebras for riding since they have better resistance than horses to African diseases.
+ </ph>
+ <ph id="113">
+ However most of these attempts failed, due to the zebra's more unpredictable nature and tendency to panic under stress.
+ </ph>
+ <ph id="114">
+ For this reason, zebra-mules or zebroids (crosses between any species of zebra and a horse, pony, donkey or ass) are preferred over pure-bred zebras.
+ </ph>
+ </p>
+ <p id="43">
+ <ph id="115">
+ In England, the zoological collector Lord Rothschild frequently used zebras to draw a carriage.
+ </ph>
+ <ph id="116">
+ In 1907, Rosendo Ribeiro, the first doctor in Nairobi, Kenya, used a riding zebra for house-calls.
+ </ph>
+ <ph id="117">
+ In the mid 1800s Governor George Grey imported zebras to New Zealand from his previous posting in South Africa, and used them to pull his carriage on his privately owned Kawau Island.
+ </ph>
+ </p>
+ <p id="44">
+ <ph id="118">
+ Captain Horace Hayes, in "Points of the Horse"
+ </ph>
+ <ph id="119">
+ (circa 1899) compared the usefulness of different zebra species.
+ </ph>
+ <ph id="120">
+ Hayes saddled and bridled a Mountain zebra in less than one hour, but was unable to give it a "mouth"
+ </ph>
+ <ph id="121">
+ during the two days it was in his possession.
+ </ph>
+ <ph id="122">
+ He noted that the zebra's neck was so stiff and strong that he was unable to bend it in any direction.
+ </ph>
+ <ph id="123">
+ Although he taught it to do what he wanted in a circus ring, when he took it outdoors he was unable to control it.
+ </ph>
+ <ph id="124">
+ He found the Burchell's zebra easy to break in and considered it ideal for domestication, as it was also immune to the bite of the tsetse fly.
+ </ph>
+ <ph id="125">
+ He considered the quagga well-suited to domestication due to being stronger, more docile and more horse-like than other zebras.
+ </ph>
+ </p>
+ <p id="45">
+ <ph id="126">
+ </ph>
+ </p>
+ </section>
+ <section id="12">
+ <title>
+ Conservation
+ </title>
+ <p id="46">
+ <ph id="127">
+ Modern man have had great impact on the zebra population since the 19th century.
+ </ph>
+ <ph id="128">
+ Zebras were, and still are, hunted mainly for their skins.
+ </ph>
+ <ph id="129">
+ The Cape mountain zebra was hunted to near extinction with less than 100 individuals by the 1930s.
+ </ph>
+ <ph id="130">
+ However the population has increased to about 700 due to conservation efforts.
+ </ph>
+ <ph id="131">
+ Both Mountain zebra subspecies are currently protected in national parks but are still endangered.
+ </ph>
+ </p>
+ <p id="47">
+ <ph id="132">
+ The Grevy's zebra is also endangered.
+ </ph>
+ <ph id="133">
+ Hunting and competition from livestock have greatly decreased their population.
+ </ph>
+ <ph id="134">
+ Because of the population's small size, environmental hazards, such as drought, are capable of easily affecting the entire species.
+ </ph>
+ <ph id="135">
+ Plains zebras are much more numerous and have a healthy population.
+ </ph>
+ <ph id="136">
+ Nevertheless they too are threatened by hunting and habitat change from farming.
+ </ph>
+ <ph id="137">
+ One subspecies, the quagga, is now extinct.
+ </ph>
+ </p>
+ <p id="48">
+ <ph id="138">
+ </ph>
+ </p>
+ </section>
+ </refbody>
+ </reference>
+ <reference id="6">
+ <title>
+ References
+ </title>
+ <refbody>
+ <section id="13">
+ <ol>
+ <li id="cite_note-0">
+ ^ TalkOrigins.org - Horse Evolution
+ </li>
+ <li id="cite_note-1">
+ ^ Gould, S. J. (1983) Hen's Teeth and Horse's Toes: Further Reflections in Natural History. New York: W. W. Norton and Company.
+ </li>
+ <li id="cite_note-2">
+ ^ Re: Is a zebra white with black stripes or black with white stripes?
+ </li>
+ <li id="cite_note-3">
+ ^ "How do a zebra's stripes act as camouflage?". How Stuff Works. Retrieved on 2006-11-13.
+ </li>
+ <li id="cite_note-4">
+ ^ Waage, J. K. (1981). How the zebra got its stripes: biting flies as selective agents in the evolution of zebra colouration. J. Entom. Soc. South Africa. 44: 351 - 358.
+ </li>
+ </ol>
+ </section>
+ <section id="14">
+ <ul>
+ <li>
+ Estes, R. (1991). The Behavior Guide to African Mammals, Including Hoofed Mammals, Carnivores, Primates. Los Angeles, The University of California Press.
+ </li>
+ <li>
+ McClintock, Dorcas. "A Natural History Of Zebras" September 1976. Scribner's, New York. ISBN 0-684-14621-5
+ </li>
+ <li>
+ Hayes, Horace. "Points of the Horse" (circa 1899)
+ </li>
+ <li>
+ Churcher, C.S. 1993. Mammalian Species No. 453. American Society of Mammalogists.
+ </li>
+ </ul>
+ </section>
+ <p id="49">
+ <ph id="139">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="7">
+ <title>
+ See also
+ </title>
+ <refbody>
+ <section id="15">
+ <ul>
+ <li>
+ Zebroid
+ </li>
+ <li>
+ Tijuana Zebra
+ </li>
+ </ul>
+ </section>
+ <p id="50">
+ <ph id="140">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="8">
+ <title>
+ External links
+ </title>
+ <refbody>
+ <section id="16">
+ <ul>
+ <li>
+ Zebra file at Encyclopedia Encarta
+ </li>
+ <li>
+ PBS Nature: Horse Tigers (Zebras)
+ </li>
+ <li>
+ Plains Zebra - Equus Burchelli
+ </li>
+ </ul>
+ </section>
+ <p id="51">
+ <ph id="141">
+ </ph>
+ </p>
+ </refbody>
+ </reference>
+ <reference id="imagelist">
+ <refbody>
+ <image href="#DEMOLIBRARY#/images/250px-Beautiful_Zebra_in_South_Africa.JPG">
+ <alt>
+ 250px-Beautiful_Zebra_in_South_Africa.JPG
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/200px-Zebra_Botswana_edit02.jpg">
+ <alt>
+ Zebras in Botswana
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Equus_grevyi_in_Kenya_%28male%29.jpg">
+ <alt>
+ Grevy's Zebra in Kenya
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-LAzooZebra.jpg">
+ <alt>
+ A Zebra in captivity at the Los Angeles Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/200px-Zebra2.jpg">
+ <alt>
+ A mother nursing her young blends into a stand of deadwood.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/200px-Zebra_rownikowa_Equus_burchelli_boehmi_RB3.jpg">
+ <alt>
+ A zebra walking
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Zoo_UL%2C_Hartmann%27s_mountain_zebra.jpg">
+ <alt>
+ Closeup of zebra face
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-Tanzanian_Animals.jpg">
+ <alt>
+ Zebras in Tanzania
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Zebra_eating.JPG">
+ <alt>
+ A zebra feeding on grass.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/180px-Zebra_Dallas_Zoo_1974.jpg">
+ <alt>
+ Mother and foal at Dallas Zoo
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/200px-Zebra-tame-jumping.jpg">
+ <alt>
+ A tamed zebra being ridden in East Africa
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/250px-WalterRothschildWithZebras.jpg">
+ <alt>
+ Lord Rothschild with his famed zebra carriage (Equus burchelli), which he frequently drove through London.
+ </alt>
+ </image>
+ <image href="#DEMOLIBRARY#/images/150px-Mare_and_foal_%28Kvetina-Marie%29.jpg">
+ <alt>
+ 150px-Mare_and_foal_%28Kvetina-Marie%29.jpg
+ </alt>
+ </image>
+ </refbody>
+ </reference>
+</reference> \ No newline at end of file
diff --git a/Stylesheets/ditastyle.css b/Stylesheets/ditastyle.css
new file mode 100644
index 0000000..1e6db73
--- /dev/null
+++ b/Stylesheets/ditastyle.css
@@ -0,0 +1,45 @@
+/* Copyright (C) IBM Corporation 2008 */
+body
+{
+background-color: #f6f6f6; /* sets the background colour for the page */
+color: #000000; /* sets the default font colour for the page */
+}
+
+p,li
+{
+font-family: arial, 'sans serif'; /* sets font */
+color: #000000; /* sets font color */
+}
+
+h1
+{
+background-color: #0000bb; /* set the background for the h1 header */
+color: #ffffff; /* sets the font colour for the h1 header */
+text-align: center; /* aligns text in the centre of the page */
+}
+
+h2,h3,h4
+{
+color: #0000dd; /* sets the font colour for the header elements */
+}
+
+img
+{
+border-style: none; /* removes the boarder around linked images */
+}
+
+a:link
+{
+color: #990000; /* sets the font colour for a:link */
+}
+
+a:visited, a:active
+{
+color: #ff5555; /* sets the font colour for these elements */
+}
+
+a:hover
+{
+color: #ff0000; /* sets the font colour for a:hover */
+}
+
diff --git a/Stylesheets/ditastylesheet.xsl b/Stylesheets/ditastylesheet.xsl
new file mode 100644
index 0000000..680fd86
--- /dev/null
+++ b/Stylesheets/ditastylesheet.xsl
@@ -0,0 +1,92 @@
+<!-- Copyright (C) IBM Corporation 2008 -->
+<?xml version="1.0"?>
+<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
+<head>
+ <title><xsl:value-of select="reference/title" /></title>
+ <link rel="stylesheet" type="text/css" href="ditastyle.css" title="Selected Stylesheet" />
+</head>
+<body>
+ <p>
+ <a href="librarymap.ditamap">Return to index</a>
+ </p>
+ <h1>
+ <xsl:value-of select="reference/title" />
+ </h1>
+
+ <p>
+ <xsl:copy-of select="reference/shortdesc" />
+ <xsl:if test="contains(reference/section/p/@id,'shortdesc')">
+ <xsl:for-each select="reference/section/p">
+ <xsl:for-each select="image">
+ <img>
+ <xsl:attribute name="src">
+ <xsl:value-of select="@href" />
+ </xsl:attribute>
+ </img>
+ </xsl:for-each>
+ <xsl:copy-of select="ph" />
+ </xsl:for-each>
+ </xsl:if>
+ </p>
+
+ <xsl:for-each select="reference/refbody">
+ <p>
+ <xsl:copy-of select="p" />
+ </p>
+ </xsl:for-each>
+
+ <xsl:for-each select="reference/reference">
+ <h2>
+ <xsl:value-of select="title" />
+ </h2>
+
+ <xsl:for-each select="refbody">
+ <h3>
+ <xsl:value-of select="title" />
+ </h3>
+ <p>
+ <xsl:value-of select="p" />
+ </p>
+ </xsl:for-each>
+
+ <xsl:for-each select="refbody/section">
+ <h3>
+ <xsl:value-of select="title" />
+ </h3>
+ <xsl:for-each select="p">
+ <p>
+ <xsl:for-each select="image">
+ <img>
+ <xsl:attribute name="src">
+ <xsl:value-of select="@href" />
+ </xsl:attribute>
+ </img>
+ </xsl:for-each>
+ <xsl:copy-of select="ph" />
+ </p>
+ </xsl:for-each>
+ </xsl:for-each>
+<xsl:comment>
+ <xsl:copy-of select="refbody/section/ul" />
+ <xsl:copy-of select="refbody/section/ol" />
+</xsl:comment>
+ </xsl:for-each>
+
+ <xsl:if test="not(contains(reference/section/p/@id,'shortdesc'))">
+ <xsl:for-each select="reference">
+ <xsl:for-each select="section/p">
+ <p>
+ <xsl:for-each select="image">
+ <img>
+ <xsl:attribute name="src">
+ <xsl:value-of select="@href" />
+ </xsl:attribute>
+ </img>
+ </xsl:for-each>
+ <xsl:copy-of select="ph" />
+ </p>
+ </xsl:for-each>
+ </xsl:for-each>
+ </xsl:if>
+</body>
+</html>
diff --git a/Stylesheets/mapstyle.css b/Stylesheets/mapstyle.css
new file mode 100644
index 0000000..a8fe772
--- /dev/null
+++ b/Stylesheets/mapstyle.css
@@ -0,0 +1,46 @@
+/* Copyright (C) IBM Corporation 2008 */
+
+body
+{
+background-color: #f6f6f6; /* sets the background colour for the page */
+color: #000000; /* sets the default font colour for the page */
+}
+
+p,li
+{
+font-family: arial, 'sans serif'; /* sets font */
+color: #000000; /* sets font color */
+}
+
+h1
+{
+background-color: #0000bb; /* set the background for the h1 header */
+color: #ffffff; /* sets the font colour for the h1 header */
+text-align: center; /* aligns text in the centre of the page */
+}
+
+h2,h3,h4
+{
+color: #0000dd; /* sets the font colour for the header elements */
+}
+
+img
+{
+border-style: none; /* removes the boarder around linked images */
+}
+
+a:link
+{
+color: #990000; /* sets the font colour for a:link */
+}
+
+a:visited, a:active
+{
+color: #ff5555; /* sets the font colour for these elements */
+}
+
+a:hover
+{
+color: #ff0000; /* sets the font colour for a:hover */
+}
+
diff --git a/Stylesheets/mapstylesheet.xsl b/Stylesheets/mapstylesheet.xsl
new file mode 100644
index 0000000..1e207a8
--- /dev/null
+++ b/Stylesheets/mapstylesheet.xsl
@@ -0,0 +1,24 @@
+<!-- Copyright (C) IBM Corporation 2008 -->
+<?xml version="1.0"?>
+<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsl:version="1.0">
+<head>
+ <title><xsl:value-of select="map/@title" /></title>
+ <link rel="stylesheet" type="text/css" href="mapstyle.css" title="Selected Stylesheet" />
+</head>
+<body>
+ <h1>
+ <xsl:value-of select="map/@title" />
+ </h1>
+
+ <xsl:for-each select="map">
+ <li>
+ <xsl:for-each select="topicref">
+ <ul><a><xsl:attribute name="href">
+ <xsl:value-of select="@href" />
+ </xsl:attribute>
+ <xsl:value-of select="@navtitle" /></a></ul>
+ </xsl:for-each>
+ </li>
+ </xsl:for-each>
+</body>
+</html>
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..ddecfb5
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,8 @@
+[Activity]
+name = InfoSlicer
+activity_version = 1
+host_version = 1
+icon = slicelogo
+service_name = org.laptop.infoslicer
+class = sugaractivity.sugaractivity
+show_launcher = yes \ No newline at end of file
diff --git a/activity/slicelogo.svg b/activity/slicelogo.svg
new file mode 100644
index 0000000..0a61e75
--- /dev/null
+++ b/activity/slicelogo.svg
@@ -0,0 +1,37 @@
+<!-- Copyright (C) IBM Corporation 2008 -->
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY stroke_color "white">
+ <!ENTITY fill_color "none">
+]>
+
+<svg xmlns="http://www.w3.org/2000/svg"
+ width="0.833333in" height="0.833333in"
+ viewBox="0 0 60 60">
+ <path id="Left"
+ fill="&fill_color;" stroke="&stroke_color;" stroke-width="3"
+ d="M 12.99,13.24
+ C 6.25,14.28 1.54,4.53 11.04,0.84
+ 21.21,0.83 20.24,12.12 12.99,13.24 Z
+ M 17.00,51.00
+ C 16.79,62.12 7.21,62.12 7.00,51.00
+ 7.00,51.00 7.00,26.00 7.00,26.00
+ 7.01,22.15 6.42,15.45 12.04,15.45
+ 16.56,15.45 27.01,25.83 28.16,30.00
+ 29.24,33.93 25.89,37.10 22.00,36.34
+ 20.41,36.03 18.42,34.79 17.00,34.00
+ 17.00,34.00 17.00,51.00 17.00,51.00 Z" />
+ <path id="Right"
+ fill="&stroke_color;" stroke="&fill_color;" stroke-width="3"
+ d="M 47.98,13.38
+ C 41.36,14.32 35.84,4.23 46.01,0.76
+ 56.42,1.03 54.51,12.46 47.98,13.38 Z
+ M 30.84,30.00
+ C 31.98,25.83 42.45,15.45 46.96,15.45
+ 52.24,15.45 51.98,21.28 52.00,25.00
+ 52.00,25.00 52.00,50.00 52.00,50.00
+ 51.92,61.19 45.67,60.59 42.85,56.77
+ 40.77,53.95 41.01,49.36 41.00,46.00
+ 41.00,46.00 41.00,34.00 41.00,34.00
+ 32.85,39.73 29.80,33.82 30.84,30.00 Z" />
+</svg>
diff --git a/docs/infoslicer-code.odt b/docs/infoslicer-code.odt
new file mode 100644
index 0000000..5aa1b0f
--- /dev/null
+++ b/docs/infoslicer-code.odt
Binary files differ
diff --git a/docs/infoslicer-directions.odt b/docs/infoslicer-directions.odt
new file mode 100644
index 0000000..874cf63
--- /dev/null
+++ b/docs/infoslicer-directions.odt
Binary files differ
diff --git a/docs/infoslicer-guipanes.odt b/docs/infoslicer-guipanes.odt
new file mode 100644
index 0000000..c32229f
--- /dev/null
+++ b/docs/infoslicer-guipanes.odt
Binary files differ
diff --git a/docs/infoslicer-overview.odt b/docs/infoslicer-overview.odt
new file mode 100644
index 0000000..445f310
--- /dev/null
+++ b/docs/infoslicer-overview.odt
Binary files differ
diff --git a/docs/tutorial-booklet-v9.pdf b/docs/tutorial-booklet-v9.pdf
new file mode 100644
index 0000000..ca75d76
--- /dev/null
+++ b/docs/tutorial-booklet-v9.pdf
Binary files differ
diff --git a/docs/tutorial-booklet.odt b/docs/tutorial-booklet.odt
new file mode 100644
index 0000000..f0fdf4c
--- /dev/null
+++ b/docs/tutorial-booklet.odt
Binary files differ
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..977ab03
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# Copyright (C) IBM Corporation 2008
+# Taken from the OLPC Wiki.
+try:
+ from sugar.activity import bundlebuilder
+ bundlebuilder.start("InfoSlicer")
+except ImportError:
+ import os
+ os.system("find ./ | sed 's,^./,InfoSlicer.activity/,g' > MANIFEST")
+ os.system('rm InfoSlicer.xo')
+ os.chdir('..')
+ os.system('zip -r InfoSlicer.xo InfoSlicer.activity')
+ os.system('mv InfoSlicer.xo ./InfoSlicer.activity')
+ os.chdir('InfoSlicer.activity') \ No newline at end of file
diff --git a/sugaractivity.py b/sugaractivity.py
new file mode 100644
index 0000000..c90bd4a
--- /dev/null
+++ b/sugaractivity.py
@@ -0,0 +1,130 @@
+# Copyright (C) IBM Corporation 2008
+
+import gtk
+from Infoslicer_GUI import Infoslicer_GUI
+from sugar.activity import activity
+from Processing.IO_Manager import IO_Manager
+
+class sugaractivity( activity.Activity, Infoslicer_GUI ):
+ """
+ Created by Jonathan Mace
+
+ This is the Sugar implementation of the infoslicer GUI.
+
+ It sets things in the sugar.activity class in the abstract methods.
+ """
+
+ """
+ Set up Sugar specific GUI config and show interface
+ """
+ def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+ gtk.gdk.threads_init()
+ gtk.gdk.threads_enter()
+ self.toolbox = activity.ActivityToolbox(self)
+ Infoslicer_GUI.__init__(self)
+ self._name = handle
+ self.toolbox.connect("current-toolbar-changed", self.page_switched, None)
+
+ self.set_title('InfoSlicer')
+
+ self.set_toolbox(self.toolbox)
+ self.toolbox.show()
+
+ self.show_all()
+ self.toolbox.set_current_toolbar(2)
+
+ print "dictionary:"
+ print handle.get_dict()
+
+ """
+ Operating system specific file reading and writing methods are below
+ """
+ def read_file(self, file_path):
+ print "reading the file"
+ """
+ At the moment, the format of a saved file will just be:
+ sourcetitle
+ edittitle
+ edittheme
+ currentindex
+ """
+
+ file = open(file_path, 'r')
+ text = file.read()
+ file.close()
+ lines = text.splitlines()
+ if len(lines) < 3:
+ return
+ sourcetitle = lines[0]
+ workingtitle = lines[1]
+ workingtheme = lines[2]
+ currentindex = lines[3]
+
+ print "file read"
+ print "sourcetitle: %s, workingtitle: %s, workingtheme: %s, currentindex: %s" % (sourcetitle, workingtitle, workingtheme, currentindex)
+ iomanager = IO_Manager()
+ if iomanager.page_exists(sourcetitle, "Wikipedia Articles"):
+ sourcearticle = iomanager.load_article(sourcetitle, "Wikipedia Articles")
+ else:
+ sourcearticle = Article()
+ sourcearticle.article_title = sourcetitle
+ sourcearticle.article_theme = "Wikipedia Articles"
+ if iomanager.page_exists(workingtitle, workingtheme):
+ workingarticle = iomanager.load_article(workingtitle, workingtheme)
+ else:
+ workingarticle = Article()
+ workingarticle.article_title = workingtitle
+ workingarticle.article_theme = workingtheme
+
+ self.switch_page(currentindex)
+
+ self.currentpane.set_source_article(sourcearticle)
+ self.currentpane.set_working_article(workingarticle)
+
+ def write_file(self, file_path):
+ print "writing the file to %s" % file_path
+ sourcearticle = self.currentpane.get_source_article()
+ workingarticle = self.currentpane.get_working_article()
+
+ sourcetitle = sourcearticle.article_title
+ if not sourcetitle:
+ sourcetitle = "none"
+ workingtitle = workingarticle.article_title
+ if not workingtitle:
+ workingtitle = "none"
+ workingtheme = workingarticle.article_theme
+ if not workingtheme:
+ workingtheme = "none"
+ currentindex = self.currentindex
+
+ file = open(file_path, 'w')
+ print "writing source: %s, working: %s, theme: %s" % (sourcetitle, workingtitle, workingtheme)
+ file.write("%s\n%s\n%s\n%s" % (sourcetitle, workingtitle, workingtheme, str(currentindex)))
+ file.close()
+
+
+
+ def settoolbars(self, toolbars, toolbarnames):
+ for i in range(0, len(toolbars)):
+ self.toolbox.add_toolbar(toolbarnames[i], toolbars[i])
+ toolbars[i].show()
+
+
+ def setpanel(self, panel):
+ self._main_view = panel
+ self.set_canvas(self._main_view)
+ self._main_view.show()
+
+
+ def page_switched(self, widget, page_num, data):
+ print "page_switched to %s" % (page_num, )
+ if page_num > 0:
+ self.mode_switched(page_num - 1)
+
+ def switch_page(self, page_num):
+ self.mode_switched(page_num)
+
+ def can_close(self):
+ self.do_quit_event()
+ return True \ No newline at end of file