├── .gitignore ├── Gemfile ├── lib ├── creole │ ├── version.rb │ └── parser.rb └── creole.rb ├── CHANGES ├── .travis.yml ├── Rakefile ├── creole.gemspec ├── README.creole └── test └── parser_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | doc 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org/' 2 | gemspec 3 | 4 | -------------------------------------------------------------------------------- /lib/creole/version.rb: -------------------------------------------------------------------------------- 1 | module Creole 2 | VERSION = '0.5.0' 3 | end 4 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 0.5.0 2 | 3 | * Remove methods make_*_anchor 4 | * Add method make_headline 5 | * Parse tags inside link text 6 | 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.8.7 4 | - 1.9.3 5 | - 2.0.0 6 | - 2.1.0 7 | - ruby-head 8 | - jruby-18mode 9 | - jruby-19mode 10 | - rbx 11 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | task :default => :test 2 | 3 | desc 'Run tests with bacon' 4 | task :test => FileList['test/*_test.rb'] do |t| 5 | sh "bacon -q -Ilib:test #{t.prerequisites.join(' ')}" 6 | end 7 | -------------------------------------------------------------------------------- /lib/creole.rb: -------------------------------------------------------------------------------- 1 | require 'creole/parser' 2 | require 'creole/version' 3 | 4 | module Creole 5 | # Convert the argument in Creole format to HTML and return the 6 | # result. Example: 7 | # 8 | # Creole.creolize("**Hello //World//**") 9 | # #=> "
Hello World
" 10 | # 11 | # This is an alias for calling Creole#parse: 12 | # Creole.new(text).to_html 13 | def self.creolize(text, options = {}) 14 | Parser.new(text, options).to_html 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /creole.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.dirname(__FILE__) + '/lib/creole/version' 3 | require 'date' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'creole' 7 | s.version = Creole::VERSION 8 | s.date = Date.today.to_s 9 | 10 | s.authors = ['Lars Christensen', 'Daniel Mendler'] 11 | s.email = ['larsch@belunktum.dk', 'mail@daniel-mendler.de'] 12 | s.summary = 'Lightweight markup language' 13 | s.description = 'Creole is a lightweight markup language (http://wikicreole.org/).' 14 | s.extra_rdoc_files = %w(README.creole) 15 | s.rubyforge_project = s.name 16 | 17 | s.files = `git ls-files`.split("\n") 18 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 19 | s.require_paths = %w(lib) 20 | 21 | s.homepage = 'http://github.com/minad/creole' 22 | s.license = 'Ruby' 23 | 24 | s.add_development_dependency('bacon') 25 | s.add_development_dependency('rake') 26 | end 27 | -------------------------------------------------------------------------------- /README.creole: -------------------------------------------------------------------------------- 1 | = Creole 2 | 3 | Creole is a Creole-to-HTML converter for Creole, the lightweight markup 4 | language (http://wikicreole.org/). Github uses this converter to render *.creole files. 5 | 6 | Project page on github: 7 | 8 | * http://github.com/minad/creole 9 | 10 | Travis-CI: 11 | 12 | * https://travis-ci.org/minad/creole 13 | 14 | RDOC: 15 | 16 | * http://rdoc.info/projects/minad/creole 17 | 18 | == INSTALLATION 19 | 20 | {{{ 21 | gem install creole 22 | }}} 23 | 24 | == SYNOPSIS 25 | 26 | {{{ 27 | require 'creole' 28 | html = Creole.creolize('== Creole text') 29 | }}} 30 | 31 | == BUGS 32 | 33 | If you found a bug, please report it at the Creole project's tracker 34 | on GitHub: 35 | 36 | http://github.com/minad/creole/issues 37 | 38 | == AUTHORS 39 | 40 | * Lars Christensen (larsch) 41 | * Daniel Mendler (minad) 42 | 43 | == LICENSE 44 | 45 | Creole is Copyright (c) 2008 - 2013 Lars Christensen, Daniel Mendler. It is free software, and 46 | may be redistributed under the terms specified in the README file of 47 | the Ruby distribution. 48 | 49 | -------------------------------------------------------------------------------- /lib/creole/parser.rb: -------------------------------------------------------------------------------- 1 | require 'cgi' 2 | require 'uri' 3 | 4 | # :main: Creole 5 | 6 | # The Creole parses and translates Creole formatted text into 7 | # XHTML. Creole is a lightweight markup syntax similar to what many 8 | # WikiWikiWebs use. Example syntax: 9 | # 10 | # = Heading 1 = 11 | # == Heading 2 == 12 | # === Heading 3 === 13 | # **Bold text** 14 | # //Italic text// 15 | # [[Links]] 16 | # |=Table|=Heading| 17 | # |Table |Cells | 18 | # {{image.png}} 19 | # 20 | # The simplest interface is Creole.creolize. The default handling of 21 | # links allow explicit local links using the [[link]] syntax. External 22 | # links will only be allowed if specified using http(s) and ftp(s) 23 | # schemes. If special link handling is needed, such as inter-wiki or 24 | # hierachical local links, you must inherit Creole::CreoleParser and 25 | # override make_local_link. 26 | # 27 | # You can customize the created image markup by overriding 28 | # make_image. 29 | 30 | # Main Creole parser class. Call CreoleParser#parse to parse Creole 31 | # formatted text. 32 | # 33 | # This class is not reentrant. A separate instance is needed for 34 | # each thread that needs to convert Creole to HTML. 35 | # 36 | # Inherit this to provide custom handling of links. The overrideable 37 | # methods are: make_local_link 38 | module Creole 39 | class Parser 40 | 41 | # Allowed url schemes 42 | # Examples: http https ftp ftps 43 | attr_accessor :allowed_schemes 44 | 45 | # Non-standard wiki text extensions enabled? 46 | # E.g. underlined, deleted text etc 47 | attr_writer :extensions 48 | def extensions?; @extensions; end 49 | 50 | # Disable url escaping for local links 51 | # Escaping: [[/Test]] --> %2FTest 52 | # No escaping: [[/Test]] --> Test 53 | attr_writer :no_escape 54 | def no_escape?; @no_escape; end 55 | 56 | # Create a new CreoleParser instance. 57 | def initialize(text, options = {}) 58 | @allowed_schemes = %w(http https ftp ftps) 59 | @text = text 60 | @extensions = @no_escape = nil 61 | options.each_pair {|k,v| send("#{k}=", v) } 62 | end 63 | 64 | # Convert CCreole text to HTML and return 65 | # the result. The resulting HTML does not contain and 66 | # tags. 67 | # 68 | # Example: 69 | # 70 | # parser = CreoleParser.new("**Hello //World//**", :extensions => true) 71 | # parser.to_html 72 | # #=> "Hello World
" 73 | def to_html 74 | @out = '' 75 | @p = false 76 | @stack = [] 77 | parse_block(@text) 78 | @out 79 | end 80 | 81 | protected 82 | 83 | # Escape any characters with special meaning in HTML using HTML 84 | # entities. 85 | def escape_html(string) 86 | CGI::escapeHTML(string) 87 | end 88 | 89 | # Escape any characters with special meaning in URLs using URL 90 | # encoding. 91 | def escape_url(string) 92 | CGI::escape(string) 93 | end 94 | 95 | def start_tag(tag) 96 | @stack.push(tag) 97 | @out << '<' << tag << '>' 98 | end 99 | 100 | def end_tag 101 | @out << '' << @stack.pop << '>' 102 | end 103 | 104 | def toggle_tag(tag, match) 105 | if @stack.include?(tag) 106 | if @stack.last == tag 107 | end_tag 108 | else 109 | @out << escape_html(match) 110 | end 111 | else 112 | start_tag(tag) 113 | end 114 | end 115 | 116 | def end_paragraph 117 | end_tag while !@stack.empty? 118 | @p = false 119 | end 120 | 121 | def start_paragraph 122 | if @p 123 | @out << ' ' if @out[-1] != ?\s 124 | else 125 | end_paragraph 126 | start_tag('p') 127 | @p = true 128 | end 129 | end 130 | 131 | # Translate an explicit local link to a desired URL that is 132 | # properly URL-escaped. The default behaviour is to convert local 133 | # links directly, escaping any characters that have special 134 | # meaning in URLs. Relative URLs in local links are not handled. 135 | # 136 | # Examples: 137 | # 138 | # make_local_link("LocalLink") #=> "LocalLink" 139 | # make_local_link("/Foo/Bar") #=> "%2FFoo%2FBar" 140 | # 141 | # Must ensure that the result is properly URL-escaped. The caller 142 | # will handle HTML escaping as necessary. HTML links will not be 143 | # inserted if the function returns nil. 144 | # 145 | # Example custom behaviour: 146 | # 147 | # make_local_link("LocalLink") #=> "/LocalLink" 148 | # make_local_link("Wikipedia:Bread") #=> "http://en.wikipedia.org/wiki/Bread" 149 | def make_local_link(link) #:doc: 150 | no_escape? ? link : escape_url(link) 151 | end 152 | 153 | # Sanatize a direct url (e.g. http://wikipedia.org/). The default 154 | # behaviour returns the original link as-is. 155 | # 156 | # Must ensure that the result is properly URL-escaped. The caller 157 | # will handle HTML escaping as necessary. Links will not be 158 | # converted to HTML links if the function returns link. 159 | # 160 | # Custom versions of this function in inherited classes can 161 | # implement specific link handling behaviour, such as redirection 162 | # to intermediate pages (for example, for notifing the user that 163 | # he is leaving the site). 164 | def make_direct_link(url) #:doc: 165 | url 166 | end 167 | 168 | # Sanatize and prefix image URLs. When images are encountered in 169 | # Creole text, this function is called to obtain the actual URL of 170 | # the image. The default behaviour is to return the image link 171 | # as-is. No image tags are inserted if the function returns nil. 172 | # 173 | # Custom version of the method can be used to sanatize URLs 174 | # (e.g. remove query-parts), inhibit off-site images, or add a 175 | # base URL, for example: 176 | # 177 | # def make_image_link(url) 178 | # URI.join("http://mywiki.org/images/", url) 179 | # end 180 | def make_image_link(url) #:doc: 181 | url 182 | end 183 | 184 | # Create image markup. This 185 | # method can be overridden to generate custom 186 | # markup, for example to add html additional attributes or 187 | # to put divs around the imgs. 188 | def make_image(uri, alt) 189 | if alt 190 | '' << escape_html(nowikiblock) << '' 325 | when /\A\s*-{4,}\s*$/ 326 | end_paragraph 327 | @out << '
This is bold
", "This **is** bold" 17 | tc "This is bold and boldish
", "This **is** bold and **bold**ish" 18 | 19 | # Creole1.0: Bold can be used inside list items 20 | tc "| This is bold |
A bold link: http://wikicreole.org/ nice!
", 28 | "A bold link: **http://wikicreole.org/ nice!**") 29 | 30 | # Creole1.0: Bold will end at the end of paragraph 31 | tc "This is bold
", "This **is bold" 32 | 33 | # Creole1.0: Bold will end at the end of list items 34 | tc("| Item bold | Another bold |
This is
bold maybe
", 43 | "This **is\n\nbold** maybe") 44 | 45 | # Creole1.0-Implied: Bold should be able to cross lines 46 | tc "This is bold
", "This **is\nbold**" 47 | end 48 | 49 | it 'should parse italic' do 50 | # Creole1.0: Italic can be used inside paragraphs 51 | tc("This is italic
", 52 | "This //is// italic") 53 | tc("This is italic and italicish
", 54 | "This //is// italic and //italic//ish") 55 | 56 | # Creole1.0: Italic can be used inside list items 57 | tc "| This is italic |
A italic link: http://wikicreole.org/ nice!
", 65 | "A italic link: //http://wikicreole.org/ nice!//") 66 | 67 | # Creole1.0: Italic will end at the end of paragraph 68 | tc "This is italic
", "This //is italic" 69 | 70 | # Creole1.0: Italic will end at the end of list items 71 | tc("| Item italic | Another italic |
This is
italic maybe
", 80 | "This //is\n\nitalic// maybe") 81 | 82 | # Creole1.0-Implied: Italic should be able to cross lines 83 | tc "This is italic
", "This //is\nitalic//" 84 | end 85 | 86 | it 'should parse bold italics' do 87 | # Creole1.0: By example 88 | tc "bold italics
", "**//bold italics//**" 89 | 90 | # Creole1.0: By example 91 | tc "bold italics
", "//**bold italics**//" 92 | 93 | # Creole1.0: By example 94 | tc "This is also good.
", "//This is **also** good.//" 95 | end 96 | 97 | it 'should parse headings' do 98 | # Creole1.0: Only three differed sized levels of heading are required. 99 | tc "== Heading 2 == foo
", " == Heading 2 == foo" 128 | tc "foo = Heading 1 =
", "foo = Heading 1 =" 132 | end 133 | 134 | it 'should parse links' do 135 | # Creole1.0: Links 136 | tc "", "[[link]]" 137 | 138 | # Creole1.0: Links can appear in paragraphs (i.e. inline item) 139 | tc "Hello, world
", "Hello, [[world]]" 140 | 141 | # Creole1.0: Named links 142 | tc "", "[[MyBigPage|Go to my page]]" 143 | 144 | # Creole1.0: URLs 145 | tc "", "[[http://www.wikicreole.org/]]" 146 | 147 | # Creole1.0: Single punctuation characters at the end of URLs 148 | # should not be considered a part of the URL. 149 | [',','.','?','!',':',';','\'','"'].each do |punct| 150 | esc_punct = CGI::escapeHTML(punct) 151 | tc "http://www.wikicreole.org/#{esc_punct}
", "http://www.wikicreole.org/#{punct}" 152 | end 153 | # Creole1.0: Nameds URLs (by example) 154 | tc("", 155 | "[[http://www.wikicreole.org/|Visit the WikiCreole website]]") 156 | 157 | # WRNING: Parsing markup within a link is optional 158 | tc "", "[[Weird Stuff|**Weird** //Stuff//]]" 159 | tc("", "[[http://example.org/|{{image.jpg}}]]") 160 | 161 | # Inside bold 162 | tc "", "**[[link]]**" 163 | 164 | # Whitespace inside [[ ]] should be ignored 165 | tc("", "[[ link ]]") 166 | tc("", "[[ link me ]]") 167 | tc("", "[[ http://dot.com/ \t| \t dot.com ]]") 168 | tc("", "[[ http://dot.com/ | dot.com ]]") 169 | end 170 | 171 | it 'should parse freestanding urls' do 172 | # Creole1.0: Free-standing URL's should be turned into links 173 | tc "", "http://www.wikicreole.org/" 174 | 175 | # URL ending in . 176 | tc "Text http://wikicreole.org. other text
", "Text http://wikicreole.org. other text" 177 | 178 | # URL ending in ), 179 | tc "Text (http://wikicreole.org), other text
", "Text (http://wikicreole.org), other text" 180 | 181 | # URL ending in ). 182 | tc "Text (http://wikicreole.org). other text
", "Text (http://wikicreole.org). other text" 183 | 184 | # URL ending in ). 185 | tc "Text (http://wikicreole.org).
", "Text (http://wikicreole.org)." 186 | 187 | # URL ending in ) 188 | tc "Text (http://wikicreole.org)
", "Text (http://wikicreole.org)" 189 | end 190 | 191 | it 'should parse paragraphs' do 192 | # Creole1.0: One or more blank lines end paragraphs. 193 | tc "This is my text.
This is more text.
", "This is\nmy text.\n\nThis is\nmore text." 194 | tc "This is my text.
This is more text.
", "This is\nmy text.\n\n\nThis is\nmore text." 195 | tc "This is my text.
This is more text.
", "This is\nmy text.\n\n\n\nThis is\nmore text." 196 | 197 | # Creole1.0: A list end paragraphs too. 198 | tc "Hello
Hello
| Cell |
Hello
nowiki", "Hello\n{{{\nnowiki\n}}}\n" 205 | 206 | # WARNING: A heading ends a paragraph (not specced) 207 | tc "
Hello
This is the first line,
and this is the second.
Par
", "* Item\n\nPar\n") 230 | 231 | # Creole1.0: An item ends at a heading 232 | tc("| Cell |
Code", "* Item\n{{{\nCode\n}}}\n") 239 | 240 | # Creole1.0: An item can span multiple lines 241 | tc("
Not bold
", 265 | "*Hello,\nWorld!\n\n**Not bold\n") 266 | end 267 | 268 | it 'should parse ordered lists' do 269 | # Creole1.0: List items begin with a * at the beginning of a line. 270 | # Creole1.0: An item ends at the next * 271 | tc "Par
", "# Item\n\nPar\n") 283 | 284 | # Creole1.0: An item ends at a heading 285 | tc("| Cell |
Code", "# Item\n{{{\nCode\n}}}\n") 292 | 293 | # Creole1.0: An item can span multiple lines 294 | tc("
This is what can go wrong:this should be an italic text.
", 348 | "This is what can go wrong://this should be an italic text//.") 349 | 350 | # A link inside italic text 351 | tc("How about a link, like http://example.org, in italic text?
", 352 | "How about //a link, like http://example.org, in italic// text?") 353 | 354 | # Another test from Creole Wiki 355 | tc("Formatted fruits, for example:apples, oranges, pears ...
", 356 | "Formatted fruits, for example://apples//, oranges, **pears** ...") 357 | end 358 | 359 | it 'should parse ambiguious bold and lists' do 360 | tc "bold text
", "** bold text **" 361 | tc "bold text
", " ** bold text **" 362 | end 363 | 364 | it 'should parse nowiki' do 365 | # ... works as block 366 | tc "Hello", "{{{\nHello\n}}}\n" 367 | 368 | # ... works inline 369 | tc "
Hello world.
", "Hello {{{world}}}." 370 | tc "Hello world.
", "{{{Hello}}} {{{world}}}." 371 | 372 | # Creole1.0: No wiki markup is interpreted inbetween 373 | tc "**Hello**", "{{{\n**Hello**\n}}}\n" 374 | 375 | # Creole1.0: Leading whitespaces are not permitted 376 | tc("
{{{ Hello }}}
", " {{{\nHello\n}}}") 377 | tc("{{{ Hello }}}
", "{{{\nHello\n }}}") 378 | 379 | # Assumed: Should preserve whitespace 380 | tc("\t Hello, \t \n \t World \t", 381 | "{{{\n \t Hello, \t \n \t World \t \n}}}\n") 382 | 383 | # In preformatted blocks ... one leading space is removed 384 | tc("
nowikiblock\n}}}", "{{{\nnowikiblock\n }}}\n}}}\n") 385 | 386 | # In inline nowiki, any trailing closing brace is included in the span 387 | tc("
this is nowiki}
", "this is {{{nowiki}}}}") 388 | tc("this is nowiki}}
", "this is {{{nowiki}}}}}") 389 | tc("this is nowiki}}}
", "this is {{{nowiki}}}}}}") 390 | tc("this is nowiki}}}}
", "this is {{{nowiki}}}}}}}") 391 | end 392 | 393 | it 'should escape html' do 394 | # Special HTML chars should be escaped 395 | tc("<b>not bold</b>
", "not bold") 396 | 397 | # Image tags should be escape 398 | tc("
** Not Bold **
", "~** Not Bold ~**" 406 | tc "// Not Italic //
", "~// Not Italic ~//" 407 | tc "* Not Bullet
", "~* Not Bullet" 408 | # Following char is not a blank (space or line feed) 409 | tc "Hello ~ world
", "Hello ~ world\n" 410 | tc "Hello ~ world
", "Hello ~\nworld\n" 411 | # Not escaping inside URLs (Creole1.0 not clear on this) 412 | tc "", "http://example.org/~user/" 413 | 414 | # Escaping links 415 | tc "http://www.wikicreole.org/
", "~http://www.wikicreole.org/" 416 | end 417 | 418 | it 'should parse horizontal rule' do 419 | # Creole: Four hyphens make a horizontal rule 420 | tc "foo ----
", "foo ----\n" 430 | tc "---- foo
", "---- foo\n" 431 | 432 | # Creole1.0: [...] no whitespace is allowed between them 433 | tc "-- --
", " -- -- " 434 | tc "-- --
", " --\t-- " 435 | end 436 | 437 | it 'should parse table' do 438 | tc "| Hello, World! |
| c1 | c2 | c3 |
| c11 | c12 |
| c21 | c22 |
| c1 | c2 | c3 |
| c1 | c3 |
| c1|c2 | c3 |
| c1 | c2| |
| c1 | c2| |
| c1 | c2| |
| Header |
|---|
| c1 | Link text |
| table |
| table |
| table |
par
", "|table|\npar\n") 465 | tc("| table |
par
", "|table|\n\npar\n") 466 | # table followed by unordered list 467 | tc("| table |
| table |
| table |
| table |
| table |
| table |
| table |
pre", "|table|\n{{{\npre\n}}}\n") 477 | tc("
| table |
pre", "|table|\n\n{{{\npre\n}}}\n") 478 | # table followed by table 479 | tc("
| table |
| table |
| table |
| table |
par
", "=heading=\npar\n") 489 | tc("par
", "=heading=\n\npar\n") 490 | # unordered list 491 | tc("nowiki", "=heading=\n{{{\nnowiki\n}}}\n") 501 | tc("
nowiki", "=heading=\n\n{{{\nnowiki\n}}}\n") 502 | # table 503 | tc("
| table |
| table |
par
par
par par
", "par\npar\n") 513 | tc("par
par
", "par\n\npar\n") 514 | # unordered 515 | tc("par
par
par
par
par
par
par
nowiki", "par\n{{{\nnowiki\n}}}\n") 525 | tc("
par
nowiki", "par\n\n{{{\nnowiki\n}}}\n") 526 | # table 527 | tc("
par
| table |
par
| table |
par
", "*item\n\npar\n") 538 | # unordered 539 | tc("nowiki", "*item\n{{{\nnowiki\n}}}\n") 549 | tc("
nowiki", "*item\n\n{{{\nnowiki\n}}}\n") 550 | # table 551 | tc("
| table |
| table |
par
", "#item\n\npar\n") 562 | # unordered 563 | tc("nowiki", "#item\n{{{\nnowiki\n}}}\n") 573 | tc("
nowiki", "#item\n\n{{{\nnowiki\n}}}\n") 574 | # table 575 | tc("
| table |
| table |
par
", "----\npar\n") 585 | tc("par
", "----\n\npar\n") 586 | # unordered 587 | tc("nowiki", "----\n{{{\nnowiki\n}}}\n") 597 | tc("
nowiki", "----\n\n{{{\nnowiki\n}}}\n") 598 | # table 599 | tc("
| table |
| table |
nowiki
nowiki
nowiki
par
", "{{{\nnowiki\n}}}\npar") 609 | tc("nowiki
par
", "{{{\nnowiki\n}}}\n\npar") 610 | # unordered 611 | tc("nowiki
nowiki
nowiki
nowiki
nowiki
nowiki
nowiki
nowiki", "{{{\nnowiki\n}}}\n{{{\nnowiki\n}}}\n") 621 | tc("
nowiki
nowiki", "{{{\nnowiki\n}}}\n\n{{{\nnowiki\n}}}\n") 622 | # table 623 | tc("
nowiki
| table |
nowiki
| table |



bold and
| table |
end
", 635 | "**bold and\n|table|\nend**") 636 | end 637 | 638 | it 'should support extensions' do 639 | tc("This is not __underlined__
", 640 | "This is not __underlined__") 641 | 642 | tce("This is underlined
", 643 | "This is __underlined__") 644 | 645 | tce("This is deleted
This is inserted
", 649 | "This is ++inserted++") 650 | 651 | tce("This is super
", 652 | "This is ^^super^^") 653 | 654 | tce("This is sub
", 655 | "This is ~~sub~~") 656 | 657 | tce("®
", "(R)") 658 | tce("®
", "(r)") 659 | tce("©
", "(C)") 660 | tce("©
", "(c)") 661 | end 662 | 663 | it 'should support no_escape' do 664 | tc("", "[[a/b/c]]") 665 | tc("", "[[a/b/c]]", :no_escape => true) 666 | end 667 | end 668 | --------------------------------------------------------------------------------