[sagenb-export] 01/02: New upstream version 2.0
Ximin Luo
infinity0 at debian.org
Sun Oct 16 17:26:59 UTC 2016
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository sagenb-export.
commit bf4c9512c278c5b5d3a80479c81572cf43ece123
Author: Ximin Luo <infinity0 at debian.org>
Date: Sun Oct 16 18:49:31 2016 +0200
New upstream version 2.0
---
.gitignore | 10 +
.travis.yml | 11 +
LICENSE | 674 +++++++++++++++++++++
MANIFEST.in | 6 +
Makefile | 11 +
README.md | 57 ++
sagenb_export/__init__.py | 0
sagenb_export/actions.py | 29 +
sagenb_export/cmdline.py | 68 +++
sagenb_export/defaults.py | 7 +
sagenb_export/ipynb_writer.py | 59 ++
sagenb_export/logger.py | 5 +
sagenb_export/nbextension/__init__.py | 32 +
sagenb_export/nbextension/asset_handler.py | 15 +
sagenb_export/nbextension/export_handler.py | 62 ++
sagenb_export/nbextension/jinja2_env.py | 15 +
sagenb_export/nbextension/list_handler.html | 57 ++
sagenb_export/nbextension/list_handler.py | 33 +
sagenb_export/nbextension/www/sagemath_icon.svg | 369 +++++++++++
sagenb_export/nbextension/www/sagenb-export.css | 124 ++++
sagenb_export/nbextension/www/sagenb-export.js | 15 +
sagenb_export/sagenb_reader.py | 178 ++++++
sagenb_export/text_writer.py | 44 ++
sagenb_export/unescape.py | 8 +
setup.py | 24 +
test/__init__.py | 0
.../10/cells/1/sage0-size500-249051951.jmol.zip | Bin 0 -> 2374 bytes
.../212/2123/admin/10/cells/1/sage0-size500.jmol | 2 +
.../10/cells/12/sage0-size500-900865605.jmol.zip | Bin 0 -> 1147 bytes
.../212/2123/admin/10/cells/12/sage0-size500.jmol | 2 +
.../21/212/2123/admin/10/snapshots/1297626260.bz2 | Bin 0 -> 100 bytes
.../21/212/2123/admin/10/snapshots/1297626396.bz2 | Bin 0 -> 162 bytes
.../21/212/2123/admin/10/snapshots/1297626546.bz2 | Bin 0 -> 293 bytes
.../21/212/2123/admin/10/snapshots/1297637968.bz2 | Bin 0 -> 603 bytes
.../21/212/2123/admin/10/snapshots/1297637997.bz2 | Bin 0 -> 1194 bytes
.../21/212/2123/admin/10/snapshots/1297648831.bz2 | Bin 0 -> 3281 bytes
.../21/212/2123/admin/10/snapshots/1297678871.bz2 | Bin 0 -> 3313 bytes
.../21/212/2123/admin/10/snapshots/1297680848.bz2 | Bin 0 -> 2677 bytes
.../2/21/212/2123/admin/10/worksheet.html | 233 +++++++
.../2/21/212/2123/admin/10/worksheet_conf.pickle | 56 ++
.../__store__/2/21/212/2123/admin/4/worksheet.html | 26 +
.../2/21/212/2123/admin/4/worksheet_conf.pickle | 58 ++
.../__store__/2/21/212/2123/admin/5/worksheet.html | 0
.../2/21/212/2123/admin/5/worksheet_conf.pickle | 66 ++
.../9/9b/9bb/9bbe/_sage_/4/worksheet.html | 282 +++++++++
.../9/9b/9bb/9bbe/_sage_/4/worksheet_conf.pickle | 61 ++
test/test_sagenb_list.py | 28 +
test/test_sagenb_reader.py | 68 +++
test/test_sagenb_writer.py | 39 ++
tox.ini | 12 +
50 files changed, 2846 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7bba8d4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+*~
+*.pyc
+.\#*
+\#*\#
+/.tox
+MANIFEST
+
+/build/
+/dist/
+/sagenb_export.egg-info/
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f5e6610
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: python
+
+env:
+- TOXENV=py27
+- TOXENV=py34
+
+install:
+- pip install tox
+
+script:
+- tox
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ef7e7ef
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ {project} Copyright (C) {year} {fullname}
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU 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. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..8c0e208
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,6 @@
+include README* LICENSE*
+recursive-include sagenb_export *.py
+recursive-include sagenb_export/nbextension *.html
+recursive-include sagenb_export/nbextension/www *
+recursive-exclude sagenb_export /#*.py .\#*.py *~
+recursive-exclude test *
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1f01b88
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+
+tox:
+ tox
+
+watch-%:
+ while true ; do \
+ $(MAKE) $* ; \
+ inotifywait -e close_write -r . --exclude '.*~' --exclude '#.*' ; \
+ done
+
+.PHONY: tox
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0a13806
--- /dev/null
+++ b/README.md
@@ -0,0 +1,57 @@
+Convert SageNB Notebooks
+========================
+
+This is a tool to convert SageNB notebooks to other formats, in
+particular IPython/Jupyter notebooks.
+
+
+Install
+-------
+
+ pip install git+https://github.com/vbraun/ExportSageNB.git
+
+or
+
+ sage -pip install git+https://github.com/vbraun/ExportSageNB.git
+
+
+Usage
+-----
+
+First, you want to list the existing notebooks. Each notebook has a
+unique id and a not necessarily unique name:
+
+ $ sagenb-export --list
+ Unique ID | Notebook Name
+ -------------------------------------------------------------------------------
+ admin:10 | Oxford Seminar (1,1)-Calabi Yau
+
+You can specify notebooks by the ID or by name; If the name is not
+unique, the first notebook found in the filesystem wins. To convert it
+to a Jupyter/IPython notebook, use the `--ipynb` switch as in
+
+ $ sagenb-export --ipynb=Output.ipynb admin:10
+
+You can then open the saved `Output.ipynb` via
+
+ $ sage --notebook=jupyter Output.ipynb
+
+
+Notes
+-----
+
+* Various output formats are not supported, e.g. no pictures. The
+ simplest solution is to re-evaluate.
+
+* SageNB html input cells are converted to Jupyter raw NBConvert
+ cells; In the interactive Jupyter notebook these are not rendered as
+ html but shown as their html source code. If you export to HTML
+ (File -> Download as -> HTML) they are rendered as html, though.
+
+
+Testing and Python Compatibility
+--------------------------------
+
+* The git-trac command supports Python 2.7, and 3.4+.
+* Most recent [Travis CI](https://travis-ci.org/vbraun/ExportSageNB) test:
+ [](https://travis-ci.org/vbraun/ExportSageNB)
diff --git a/sagenb_export/__init__.py b/sagenb_export/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sagenb_export/actions.py b/sagenb_export/actions.py
new file mode 100644
index 0000000..c78e5df
--- /dev/null
+++ b/sagenb_export/actions.py
@@ -0,0 +1,29 @@
+
+import sys
+from sagenb_export.logger import log
+from sagenb_export.sagenb_reader import NotebookSageNB
+
+
+def action_list(dot_sage):
+ def tr(unique_id, name):
+ print(u'{0:<15} | {1}'.format(unique_id, name))
+ tr('Unique ID', 'Notebook Name')
+ print('-' * 79)
+ notebooks = dict(
+ (notebook.sort_key, notebook)
+ for notebook in NotebookSageNB.all_iter(dot_sage)
+ )
+ for key in sorted(notebooks.keys()):
+ notebook = notebooks[key]
+ tr(notebook.unique_id, notebook.name)
+
+
+
+def action_print(sagenb):
+ from sagenb_export.text_writer import TextWriter
+ TextWriter(sagenb).write(sys.stdout)
+
+
+def action_convert_ipynb(sagenb, ipynb_filename):
+ from sagenb_export.ipynb_writer import IpynbWriter
+ IpynbWriter(sagenb).write(ipynb_filename)
diff --git a/sagenb_export/cmdline.py b/sagenb_export/cmdline.py
new file mode 100644
index 0000000..850e08b
--- /dev/null
+++ b/sagenb_export/cmdline.py
@@ -0,0 +1,68 @@
+## -*- encoding: utf-8 -*-
+"""
+Handle Command Line Options
+"""
+
+import os
+import sys
+import argparse
+
+from sagenb_export.defaults import DOT_SAGE
+from sagenb_export.logger import log
+from sagenb_export.sagenb_reader import NotebookSageNB
+from sagenb_export.actions import action_list, action_print, action_convert_ipynb
+
+
+description = \
+"""
+Export SageNB notebooks
+"""
+
+
+def make_parser():
+ parser = argparse.ArgumentParser(description=description)
+ parser.add_argument('--log', dest='log', default=None,
+ help='one of [DEBUG, INFO, ERROR, WARNING, CRITICAL]')
+ parser.add_argument('--dot-sage', dest='dot_sage', default=DOT_SAGE,
+ help='location of the .sage directory')
+ parser.add_argument('--list', dest='list', action='store_true',
+ help='list all SageNB notebooks')
+ parser.add_argument('--ipynb', dest='ipynb', default=None,
+ help='output .ipynb notebook filename')
+ parser.add_argument('--print', dest='print_text', action='store_true',
+ help='print notebook')
+ parser.add_argument('sagenb', default=None, nargs='?',
+ help='SageNB notebook name or unique id')
+ return parser
+
+
+
+def main():
+ parser = make_parser()
+ args = parser.parse_args()
+ if args.log is not None:
+ import logging
+ level = getattr(logging, args.log)
+ log.setLevel(level=level)
+ dot_sage = os.path.expanduser(args.dot_sage)
+ if args.list:
+ action_list(dot_sage)
+
+ if not args.sagenb:
+ sys.exit(0)
+ sagenb = NotebookSageNB.find(dot_sage, args.sagenb)
+
+ if args.print_text:
+ action_print(sagenb)
+
+ if args.ipynb:
+ ipynb_name = args.ipynb.format(nb=sagenb)
+ if os.path.exists(ipynb_name):
+ raise RuntimeError('file exists: {0}'.format(ipynb_name))
+ action_convert_ipynb(sagenb, ipynb_name)
+
+
+
+
+if __name__ == '__main__':
+ main()
diff --git a/sagenb_export/defaults.py b/sagenb_export/defaults.py
new file mode 100644
index 0000000..e6de613
--- /dev/null
+++ b/sagenb_export/defaults.py
@@ -0,0 +1,7 @@
+## -*- encoding: utf-8 -*-
+"""
+Default Values
+"""
+
+
+DOT_SAGE = '~/.sage'
diff --git a/sagenb_export/ipynb_writer.py b/sagenb_export/ipynb_writer.py
new file mode 100644
index 0000000..34a095c
--- /dev/null
+++ b/sagenb_export/ipynb_writer.py
@@ -0,0 +1,59 @@
+
+
+from nbformat import write
+from nbformat.v4 import (
+ new_code_cell, new_markdown_cell,
+ new_notebook,
+ new_output
+)
+from nbformat.v4.nbbase import new_raw_cell
+
+
+from sagenb_export.logger import log
+from sagenb_export.sagenb_reader import TextCell, ComputeCell
+
+
+class IpynbWriter(object):
+
+ def __init__(self, sagenb):
+ self.nb = sagenb
+
+
+ @property
+ def cells(self):
+ for cell in self.nb.cells:
+ if isinstance(cell, TextCell):
+ yield new_markdown_cell(
+ source=cell.input,
+ )
+ elif isinstance(cell, ComputeCell):
+ yield new_code_cell(
+ source=cell.input,
+ execution_count=cell.index,
+ outputs=[
+ new_output(
+ output_type=u'execute_result',
+ data={
+ 'text/plain': cell.output,
+ },
+ execution_count=cell.index,
+ )
+ ]
+ )
+ else:
+ log.critical('unknown cell: {0}'.format(cell))
+
+
+ def write(self, filename):
+ ipynb = new_notebook(
+ cells=list(self.cells),
+ metadata=dict(
+ kernelspec=dict(
+ display_name="SageMath",
+ name="sagemath",
+ ),
+ language='python',
+ )
+ )
+ write(ipynb, filename)
+
diff --git a/sagenb_export/logger.py b/sagenb_export/logger.py
new file mode 100644
index 0000000..89a232e
--- /dev/null
+++ b/sagenb_export/logger.py
@@ -0,0 +1,5 @@
+
+import logging
+logging.basicConfig()
+
+log = logging.getLogger('sagenb-export')
diff --git a/sagenb_export/nbextension/__init__.py b/sagenb_export/nbextension/__init__.py
new file mode 100644
index 0000000..69ea7f3
--- /dev/null
+++ b/sagenb_export/nbextension/__init__.py
@@ -0,0 +1,32 @@
+
+from tornado.web import StaticFileHandler
+
+from notebook.utils import url_path_join
+
+from sagenb_export.nbextension.list_handler import ListSageNBHandler
+from sagenb_export.nbextension.export_handler import ExportSageNBHandler
+from sagenb_export.nbextension.asset_handler import AssetHandler
+
+
+
+
+def load_jupyter_server_extension(nb_server_app):
+ """
+ Called when the extension is loaded.
+
+ Args:
+ nb_server_app (NotebookWebApplication): handle to the Notebook webserver instance.
+ """
+ web_app = nb_server_app.web_app
+ host_pattern = '.*$'
+ def url(path):
+ return url_path_join(web_app.settings['base_url'], path)
+ web_app.add_handlers(
+ host_pattern, [
+ (url(r'/sagenb'), ListSageNBHandler),
+ (url(r'/sagenb/export'), ExportSageNBHandler),
+ (url(r'/sagenb/www/(.*)'), AssetHandler),
+ ]
+ )
+
+
diff --git a/sagenb_export/nbextension/asset_handler.py b/sagenb_export/nbextension/asset_handler.py
new file mode 100644
index 0000000..3df77b0
--- /dev/null
+++ b/sagenb_export/nbextension/asset_handler.py
@@ -0,0 +1,15 @@
+
+import os
+from tornado.web import StaticFileHandler
+
+from notebook.base.handlers import FileFindHandler
+
+
+class AssetHandler(FileFindHandler):
+
+ def initialize(self, **kwds):
+ kwds['path'] = [
+ os.path.join(os.path.dirname(__file__), 'www'),
+ ]
+ super(AssetHandler, self).initialize(**kwds)
+
diff --git a/sagenb_export/nbextension/export_handler.py b/sagenb_export/nbextension/export_handler.py
new file mode 100644
index 0000000..c202910
--- /dev/null
+++ b/sagenb_export/nbextension/export_handler.py
@@ -0,0 +1,62 @@
+import os
+import string
+
+from notebook.base.handlers import IPythonHandler
+
+from sagenb_export.defaults import DOT_SAGE
+from sagenb_export.logger import log
+from sagenb_export.sagenb_reader import NotebookSageNB
+from sagenb_export.ipynb_writer import IpynbWriter
+
+
+
+def filename_escape(name):
+ def escape(ch):
+ if ch in string.ascii_letters + string.digits:
+ return ch
+ else:
+ return '_'
+ return ''.join(map(escape, name))
+
+
+
+
+class ExportSageNBHandler(IPythonHandler):
+ """
+ Return a web page that lists the current SageNB worksheets
+ """
+
+ @property
+ def dot_sage(self):
+ return os.path.expanduser(DOT_SAGE)
+
+
+ def post(self):
+ print('POST', self.request, self.request.body)
+ ipynb_filename = self.safe_filename()
+ IpynbWriter(self.notebook()).write(ipynb_filename)
+ relative_url = '/notebooks/' + ipynb_filename
+ self.finish(relative_url)
+
+ @property
+ def unique_id(self):
+ return self.request.body
+
+ def notebook(self):
+ try:
+ nb = self._notebook
+ except AttributeError:
+ nb = self._notebook = NotebookSageNB.find(self.dot_sage, self.unique_id)
+ return nb
+
+ def safe_filename(self):
+ basename = filename_escape(self.notebook().name)
+ filename = '{0}.ipynb'.format(basename)
+ if not os.path.exists(filename):
+ return filename
+ i = 2
+ while True:
+ filename = '{0} ({1}).ipynb'.format(basename, i)
+ if not os.path.exists(filename):
+ return filename
+
diff --git a/sagenb_export/nbextension/jinja2_env.py b/sagenb_export/nbextension/jinja2_env.py
new file mode 100644
index 0000000..bbfc265
--- /dev/null
+++ b/sagenb_export/nbextension/jinja2_env.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+"""
+Jinja2 Environment for Embedded Pages
+"""
+
+import os
+from jinja2 import Environment, FileSystemLoader
+
+
+jinja2_env = Environment(
+ loader=FileSystemLoader([
+ os.path.dirname(__file__)
+ ]),
+ autoescape=True,
+)
diff --git a/sagenb_export/nbextension/list_handler.html b/sagenb_export/nbextension/list_handler.html
new file mode 100644
index 0000000..ffdbe4e
--- /dev/null
+++ b/sagenb_export/nbextension/list_handler.html
@@ -0,0 +1,57 @@
+<html>
+ <head>
+ <title>SageMath</title>
+ <link rel="stylesheet" href="/sagenb/www/sagenb-export.css"/>
+ <script type="text/javascript" src="/sagenb/www/sagenb-export.js"></script>
+ </head>
+ <body>
+
+ <div class="header">
+ <h1>Sage Mathematics Software</h1>
+ <img src="/sagenb/www/sagemath_icon.svg">
+ </div>
+
+ <div class="warn">
+ <p>
+ <b>Note:</b>
+ The Sage notebook changed.
+ </p>
+ <a href="/tree">Take me to the new Sage/Jupyter notebook</a>
+ </div>
+
+ <div class="old">
+ <p>
+ To skip this screen and go directly to the new
+ notebook, run
+ </p>
+ <pre>sage --notebook=jupyter</pre>
+ <p>
+ To launch the old notebook instead, run
+ </p>
+ <pre>sage --notebook=sagenb</pre>
+ <p>
+ on the command line. Or click on one of your old
+ notebooks below to convert your old notebook to a new
+ Sage/Jupyter notebook.
+ </p>
+ </div>
+
+ <div class="error">
+ </div>
+
+ <div class="nb-list">
+ <div class="nb-row nb-header">
+ <div class="nb-id">ID</div>
+ <div class="nb-name">Name</div>
+ </div>
+ {% for nb in notebooks %}
+ <div class="nb-row clickable" onclick="exportSageNB('{{nb.unique_id}}')">
+ <div class="nb-id"><span class="ellipsis">{{ nb.unique_id }}</span></div>
+ <div class="nb-name"><span class="ellipsis">{{ nb.name }}</span></div>
+ </div>
+ {% endfor %}
+ </div>
+
+ </body>
+</html>
+
diff --git a/sagenb_export/nbextension/list_handler.py b/sagenb_export/nbextension/list_handler.py
new file mode 100644
index 0000000..eec6491
--- /dev/null
+++ b/sagenb_export/nbextension/list_handler.py
@@ -0,0 +1,33 @@
+import os
+
+from notebook.base.handlers import IPythonHandler
+
+from sagenb_export.defaults import DOT_SAGE
+from sagenb_export.logger import log
+from sagenb_export.sagenb_reader import NotebookSageNB
+from sagenb_export.nbextension.jinja2_env import jinja2_env
+
+
+
+class ListSageNBHandler(IPythonHandler):
+ """
+ Return a web page that lists the current SageNB worksheets
+ """
+
+ def notebook_iter(self):
+ dot_sage = os.path.expanduser(DOT_SAGE)
+ notebooks = dict(
+ (notebook.sort_key, notebook)
+ for notebook in NotebookSageNB.all_iter(dot_sage)
+ )
+ for key in sorted(notebooks.keys()):
+ yield notebooks[key]
+
+ def get(self):
+ template = jinja2_env.get_template('list_handler.html')
+ html = template.render(dict(
+ notebooks=tuple(self.notebook_iter()),
+ ))
+ self.finish(html)
+
+
diff --git a/sagenb_export/nbextension/www/sagemath_icon.svg b/sagenb_export/nbextension/www/sagemath_icon.svg
new file mode 100644
index 0000000..014e5e7
--- /dev/null
+++ b/sagenb_export/nbextension/www/sagemath_icon.svg
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="400"
+ height="400"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="sagemath-icon.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0"
+ inkscape:export-filename="/users/schilly/Dokumente/sage/sagemath-icon-16.png"
+ inkscape:export-xdpi="3.5999999"
+ inkscape:export-ydpi="3.5999999">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.9899495"
+ inkscape:cx="206.64893"
+ inkscape:cy="205.58295"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1280"
+ inkscape:window-height="968"
+ inkscape:window-x="-5"
+ inkscape:window-y="-3" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <rect
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ style="fill:#1919bf;fill-opacity:0.94117647;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect5084"
+ width="400"
+ height="399.99997"
+ x="0"
+ y="1.5258789e-05"
+ rx="37.939529"
+ ry="37.939529" />
+ <g
+ transform="matrix(2.514339,0,0,2.5959441,-3731.0374,-5840.643)"
+ id="g5086">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5088"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.9672595,0,0,0.9672595,235.69886,548.04605)" />
+ <path
+ transform="matrix(0.9672595,0,0,0.9672595,308.74604,539.35166)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5090"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5092"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(1.2053547,0,0,1.2053547,-25.196551,182.19849)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5094"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.7953719,0,0,0.7953719,449.34462,925.45441)" />
+ <path
+ transform="matrix(0.7953719,0,0,0.7953719,499.30379,973.24771)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5096"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5098"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.7953719,0,0,0.7953719,556.29908,956.69427)" />
+ <path
+ transform="matrix(0.7953719,0,0,0.7953719,581.00221,902.90894)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5100"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5102"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.6234843,0,0,0.6234843,800.65848,1180.6657)" />
+ <path
+ transform="matrix(0.6234843,0,0,0.6234843,766.33259,1139.9519)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5104"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5106"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.6234843,0,0,0.6234843,664.75027,1230.1938)" />
+ <path
+ transform="matrix(0.6234843,0,0,0.6234843,701.58781,1267.5497)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5108"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.7953719,0,0,0.7953719,440.41431,869.81028)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5110"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5112"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.7953719,0,0,0.7953719,484.50773,829.39633)" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5114"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.6234843,0,0,0.6234843,699.00639,1196.6154)" />
+ <path
+ transform="matrix(0.6234843,0,0,0.6234843,749.0301,1256.3969)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5116"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1590.0065,2271.6035 L 1571.3784,2344.2766"
+ id="path5118" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1589.0995,2273.5223 L 1516.5407,2281.9768"
+ id="path5120" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1571.3087,2343.4372 L 1516.6105,2281.5571"
+ id="path5122" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1571.3087,2343.8569 L 1553.2387,2399.8009"
+ id="path5124" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1516.4012,2281.3172 L 1537.4014,2256.9729"
+ id="path5126" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1493.9359,2295.4681 L 1515.7035,2281.1374"
+ id="path5128" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1503.0057,2350.6326 L 1516.4012,2280.6577"
+ id="path5130" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1552.1922,2398.5417 L 1502.6569,2351.9517"
+ id="path5132" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1610.0997,2381.3328 L 1551.9829,2398.3018"
+ id="path5134" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1634.2395,2328.3869 L 1610.0997,2381.5126"
+ id="path5136" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1570.5412,2343.4372 L 1633.4023,2328.8066"
+ id="path5138" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1590.1461,2273.0426 L 1633.2627,2328.207"
+ id="path5140" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1501.7987,2350.6326 L 1568.7761,2343.4372"
+ id="path5142" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1551.4038,2398.062 L 1526.985,2384.9304"
+ id="path5144" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1489.38,2347.2747 L 1525.7292,2384.5707"
+ id="path5146" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1493.2173,2295.9478 L 1490.4963,2347.2747"
+ id="path5148" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1537.3805,2254.8743 L 1591.4507,2256.7331"
+ id="path5150" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1627.172,2298.5261 L 1592.9158,2256.5532"
+ id="path5152" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1635.4744,2328.207 L 1626.4743,2298.1064"
+ id="path5154" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1589.4972,2272.2631 L 1592.7065,2256.9729"
+ id="path5156" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1503.6825,2351.2305 L 1489.5196,2348.5322"
+ id="path5158" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1526.985,2385.4084 L 1573.7296,2373.9558"
+ id="path5160" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1574.9157,2373.8958 L 1608.5439,2381.1512"
+ id="path5162" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1492.5121,2295.941 L 1553.7151,2289.0932"
+ id="path5164" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1553.7151,2287.7387 L 1590.1392,2274.1935"
+ id="path5166" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path5168"
+ sodipodi:cx="1324.929"
+ sodipodi:cy="1792.4095"
+ sodipodi:rx="7.3256478"
+ sodipodi:ry="7.3256478"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ transform="matrix(0.6234843,0,0,0.6234843,726.86911,1170.9368)" />
+ <path
+ transform="matrix(0.5833906,0,0,0.5833906,837.2333,1298.2147)"
+ d="M 1332.2546,1792.4095 A 7.3256478,7.3256478 0 1 1 1317.6033,1792.4095 A 7.3256478,7.3256478 0 1 1 1332.2546,1792.4095 z"
+ sodipodi:ry="7.3256478"
+ sodipodi:rx="7.3256478"
+ sodipodi:cy="1792.4095"
+ sodipodi:cx="1324.929"
+ id="path5170"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1609.6576,2343.739 L 1626.0616,2297.6751"
+ id="path5172" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1609.4298,2381.481 L 1609.9994,2342.711"
+ id="path5174" />
+ <path
+ id="path5176"
+ d="M 1502.1919,2350.0723 L 1525.6258,2314.115"
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ id="path5178"
+ d="M 1537.8572,2255.3651 L 1524.94,2314.115"
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ </g>
+</svg>
diff --git a/sagenb_export/nbextension/www/sagenb-export.css b/sagenb_export/nbextension/www/sagenb-export.css
new file mode 100644
index 0000000..14753b2
--- /dev/null
+++ b/sagenb_export/nbextension/www/sagenb-export.css
@@ -0,0 +1,124 @@
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ padding: 0;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+}
+
+h1 {
+ text-align: center;
+ font-size: 48px;
+ font-weight: normal;
+}
+
+p {
+ margin: 0;
+ padding: 0;
+}
+
+.header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ align-items: center;
+ height: 128px;
+}
+
+.header h1 {
+ flex: 8 1 0;
+ margin: auto;
+}
+
+.header img {
+ flex: 2 0 0;
+ margin: auto;
+ height: 64px;
+}
+
+.warn {
+ width: 60%;
+ margin: auto;
+ border: 2px solid #ff7f7f;
+ background: #ffdddd;
+ border-radius: 10px;
+ padding: 1em 3em;
+}
+
+.warn a {
+ padding-top: 1em;
+ display: block;
+ text-align: center;
+}
+
+.error {
+ background-color: #7f0000;
+ color: #ccffcc;
+ padding: 0 2em;
+}
+
+.old {
+ padding: 0 3em;
+ margin-top: 2em;
+ margin-bottom: 2em;
+}
+
+.old pre {
+ font-size: 130%;
+ text-align: center;
+}
+
+
+.ellipsis {
+ width: 100%;
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.nb-row.nb-header {
+ font-weight: bold;
+ text-align: center;
+ background-color: #7f7f7f !important;
+ color: #ffffff;
+}
+
+
+.nb-row {
+ display: flex;
+ flex-direction: row;
+ line-height: 48px;
+ white-space: nowrap;
+}
+
+.nb-row:nth-child(even) {
+ background: #FFF;
+}
+
+.nb-row:nth-child(odd) {
+ background: #eee;
+}
+
+.nb-row.clickable:hover {
+ background: #aaaaff;
+ cursor: pointer;
+}
+
+.nb-id {
+ padding: 0 1em 0 2em;
+ display: flex;
+ flex: 1 0 0;
+ font-family: "Lucida Console", Monaco, monospace;
+}
+
+.nb-name {
+ padding: 0 2em 0 1em;
+ display: flex;
+ flex: 8 1 0;
+}
diff --git a/sagenb_export/nbextension/www/sagenb-export.js b/sagenb_export/nbextension/www/sagenb-export.js
new file mode 100644
index 0000000..a0e1d6c
--- /dev/null
+++ b/sagenb_export/nbextension/www/sagenb-export.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var exportSageNB = function(uniqueId) {
+ console.log('Converting ' + uniqueId);
+ var xhttp = new XMLHttpRequest();
+ xhttp.onreadystatechange = function() {
+ if (xhttp.readyState == 4 && xhttp.status == 200) {
+ document.location = 'http://' + document.location.host + xhttp.responseText;
+ } else {
+ document.querySelector('.error').innerText = xhttp.responseText;
+ }
+ };
+ xhttp.open('POST', '/sagenb/export', true);
+ xhttp.send(uniqueId);
+};
diff --git a/sagenb_export/sagenb_reader.py b/sagenb_export/sagenb_reader.py
new file mode 100644
index 0000000..ef98e3d
--- /dev/null
+++ b/sagenb_export/sagenb_reader.py
@@ -0,0 +1,178 @@
+
+import os
+import re
+
+try:
+ # Python 2
+ import cPickle as pickle
+except ImportError:
+ # Python 3
+ import pickle
+
+from sagenb_export.logger import log
+from sagenb_export.unescape import unescape
+
+
+CELL_FRONT = re.compile(u'^\{\{\{id=(?P<index>[0-9]*)\|$')
+CELL_MID = re.compile(u'^///$')
+CELL_BACK = re.compile(u'^\}\}\}$')
+
+
+
+class Cell(object):
+
+ def __init__(self, input):
+ self.input = input
+
+ def __repr__(self):
+ return '{0}:"{1}"'.format(type(self), self.input.encode('utf-8', 'replace'))
+
+class ComputeCell(Cell):
+
+ def __init__(self, index, input, output):
+ assert index >= 0
+ super(ComputeCell, self).__init__(input)
+ self.index = index
+ self.output = output
+
+
+class TextCell(Cell):
+ pass
+
+
+
+class WorksheetParser(object):
+
+ def __init__(self, worksheet_html):
+ self.worksheet_lines = worksheet_html.splitlines()
+ self.pos = 0
+ self.index = -1
+ log.debug('Worksheet has %s lines', len(self.worksheet_lines))
+
+ @property
+ def line(self):
+ return self.worksheet_lines[self.pos]
+
+ def get_line_and_forward(self):
+ line = self.line
+ self.pos += 1
+ return line
+
+ @property
+ def is_finished(self):
+ return self.pos >= len(self.worksheet_lines)
+
+ @property
+ def is_cell_front(self):
+ match = CELL_FRONT.match(self.line)
+ if match:
+ self.index = int(match.group('index'))
+ return True
+ else:
+ return False
+
+ @property
+ def is_cell_mid(self):
+ match = CELL_MID.match(self.line)
+ return match != None
+
+ @property
+ def is_cell_back(self):
+ match = CELL_BACK.match(self.line)
+ return match != None
+
+ def _try_read_text(self):
+ accumulator = []
+ while not (self.is_cell_front or self.is_finished):
+ log.debug('Read text: %s', self.line)
+ accumulator.append(self.get_line_and_forward())
+ accumulator = u'\n'.join(accumulator).strip()
+ if accumulator:
+ return TextCell(unescape(accumulator))
+
+ def _read_cell_input(self):
+ assert self.is_cell_front
+ self.pos += 1
+ accumulator = []
+ while not (self.is_cell_mid or self.is_finished):
+ log.debug('Read cell input: %s', self.line)
+ accumulator.append(self.get_line_and_forward())
+ return unescape(u'\n'.join(accumulator).strip())
+
+ def _read_cell_output(self):
+ assert self.is_cell_mid
+ self.pos += 1
+ accumulator = []
+ while not (self.is_cell_back or self.is_finished):
+ log.debug('Read cell output: %s', self.line)
+ accumulator.append(self.get_line_and_forward())
+ return unescape(u'\n'.join(accumulator).strip())
+
+ def _read_cell(self):
+ input = self._read_cell_input()
+ output = self._read_cell_output()
+ return ComputeCell(self.index, input, output)
+
+ def __iter__(self):
+ while not self.is_finished:
+ text = self._try_read_text()
+ if text:
+ yield text
+ yield self._read_cell()
+ if not self.is_finished:
+ assert self.is_cell_back
+ self.pos += 1
+
+
+
+class NotebookSageNB(object):
+
+ def __init__(self, path):
+ log.debug('opening notebook root directory: %s', path)
+ self.path = path
+ with open(os.path.join(path, 'worksheet.html'), 'rb') as f:
+ self.ws = f.read().decode('utf-8')
+ with open(os.path.join(path, 'worksheet_conf.pickle'), 'rb') as f:
+ self.conf = pickle.load(f)
+
+ def __repr__(self):
+ return '{0}:"{1}"'.format(self.unique_id, self.name.encode('utf-8', 'replace'))
+
+ @classmethod
+ def all_iter(cls, dot_sage):
+ store = os.path.join(dot_sage, 'sage_notebook.sagenb', 'home', '__store__')
+ for path, dirs, files in os.walk(store):
+ worksheet = os.path.join(path, 'worksheet.html')
+ if os.path.isfile(worksheet):
+ yield cls(path)
+
+ @classmethod
+ def find(cls, dot_sage, name_or_unique_id):
+ for notebook in cls.all_iter(dot_sage):
+ if notebook.unique_id == name_or_unique_id:
+ return notebook
+ if notebook.name == name_or_unique_id:
+ return notebook
+ raise ValueError('no such notebook: {0}'.format(name_or_unique_id))
+
+ @property
+ def sort_key(self):
+ return (self.conf['owner'], self.conf['id_number'])
+
+ def __lt__(lhs, rhs):
+ return lhs.sort_key < rhs.sort_key
+
+ @property
+ def unique_id(self):
+ return '{0}:{1}'.format(self.conf['owner'], self.conf['id_number'])
+
+ @property
+ def name(self):
+ return self.conf['name']
+
+ @property
+ def cells(self):
+ for cell in WorksheetParser(self.ws):
+ log.debug('Cell: %s', cell)
+ yield cell
+
diff --git a/sagenb_export/text_writer.py b/sagenb_export/text_writer.py
new file mode 100644
index 0000000..4d4e63c
--- /dev/null
+++ b/sagenb_export/text_writer.py
@@ -0,0 +1,44 @@
+
+from sagenb_export.logger import log
+from sagenb_export.sagenb_reader import TextCell, ComputeCell
+
+
+HEADER = u"""
+Name: {nb.name}
+"""
+
+TEXT_CELL = u"""
+Text: {cell.input}
+"""
+
+
+COMPUTE_CELL = u"""
+In[{cell.index}]: {cell.input}
+Out[{cell.index}]: {cell.output}
+"""
+
+
+class TextWriter(object):
+
+ def __init__(self, sagenb):
+ self.nb = sagenb
+
+ @property
+ def header(self):
+ return HEADER.format(nb=self.nb)
+
+ @property
+ def cells(self):
+ for cell in self.nb.cells:
+ if isinstance(cell, TextCell):
+ yield TEXT_CELL.format(cell=cell)
+ elif isinstance(cell, ComputeCell):
+ yield COMPUTE_CELL.format(cell=cell)
+ else:
+ log.critical('unknown cell: {0}'.format(cell))
+
+ def write(self, stream):
+ stream.write(self.header)
+ for cell in self.cells:
+ stream.write(cell)
+
diff --git a/sagenb_export/unescape.py b/sagenb_export/unescape.py
new file mode 100644
index 0000000..a329698
--- /dev/null
+++ b/sagenb_export/unescape.py
@@ -0,0 +1,8 @@
+
+try:
+ # python 3
+ from html import unescape
+except ImportError:
+ # python 2
+ import HTMLParser
+ unescape = HTMLParser.HTMLParser().unescape
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..0530977
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+from setuptools import setup, find_packages
+
+setup(
+ name='sagenb_export',
+ description='Export Notebooks from SageNB',
+ author='Volker Braun',
+ author_email='vbraun.name at gmail.com',
+ install_requires=[
+ 'six',
+ 'ipython>=4',
+ 'nbconvert>=4',
+ ],
+ packages=find_packages(),
+ include_package_data=True,
+ entry_points={
+ 'console_scripts': [
+ 'sagenb-export = sagenb_export.cmdline:main',
+ ],
+ },
+ version='2.0',
+ url='https://github.com/vbraun/ExportSageNB',
+)
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/1/sage0-size500-249051951.jmol.zip b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/1/sage0-size500-249051951.jmol.zip
new file mode 100755
index 0000000..c6732e7
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/1/sage0-size500-249051951.jmol.zip differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/1/sage0-size500.jmol b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/1/sage0-size500.jmol
new file mode 100755
index 0000000..34ccaf5
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/1/sage0-size500.jmol
@@ -0,0 +1,2 @@
+set defaultdirectory "sage0-size500-249051951.jmol.zip"
+script SCRIPT
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/12/sage0-size500-900865605.jmol.zip b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/12/sage0-size500-900865605.jmol.zip
new file mode 100755
index 0000000..3f89e14
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/12/sage0-size500-900865605.jmol.zip differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/12/sage0-size500.jmol b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/12/sage0-size500.jmol
new file mode 100755
index 0000000..b46d1b5
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/cells/12/sage0-size500.jmol
@@ -0,0 +1,2 @@
+set defaultdirectory "sage0-size500-900865605.jmol.zip"
+script SCRIPT
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626260.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626260.bz2
new file mode 100644
index 0000000..e4d0260
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626260.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626396.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626396.bz2
new file mode 100644
index 0000000..cfdb776
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626396.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626546.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626546.bz2
new file mode 100644
index 0000000..6983ab2
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297626546.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297637968.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297637968.bz2
new file mode 100644
index 0000000..e834ae1
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297637968.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297637997.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297637997.bz2
new file mode 100644
index 0000000..dcb6159
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297637997.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297648831.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297648831.bz2
new file mode 100644
index 0000000..a4879d3
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297648831.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297678871.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297678871.bz2
new file mode 100644
index 0000000..85df33c
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297678871.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297680848.bz2 b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297680848.bz2
new file mode 100644
index 0000000..d685cd6
Binary files /dev/null and b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/snapshots/1297680848.bz2 differ
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/worksheet.html b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/worksheet.html
new file mode 100644
index 0000000..8911a2a
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/worksheet.html
@@ -0,0 +1,233 @@
+
+
+<h1 style="text-align: center;">The 24-Cell</h1>
+
+{{{id=4|
+cell24 = polytopes.twenty_four_cell()
+cell24.f_vector() # it is self-dual
+///
+(1, 24, 96, 96, 24, 1)
+}}}
+
+{{{id=86|
+cell24.f_vector?
+///
+<html><!--notruncate-->
+
+<div class="docstring">
+
+ <p><strong>File:</strong> /home/vbraun/Sage/sage/local/lib/python2.6/site-packages/sage/geometry/polyhedra.py</p>
+<p><strong>Type:</strong> <type ‘instancemethod’></p>
+<p><strong>Definition:</strong> cell24.f_vector()</p>
+<p><strong>Docstring:</strong></p>
+<blockquote>
+<p>Return the f-vector.</p>
+<p>OUTPUT:</p>
+<p>Returns a vector whose <tt class="docutils literal"><span class="pre">i</span></tt>-th entry is the number of
+<tt class="docutils literal"><span class="pre">i</span></tt>-dimensional faces of the polytope.</p>
+<p>EXAMPLES:</p>
+<div class="highlight-python"><div class="highlight"><pre class="literal-block"><span class="gp">sage: </span><span class="n">p</span> <span class="o">=</span> <span class="n">Polyhedron</span><span class="p">(</span><span class="n">vertices</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">1 [...]
+<span class="gp">sage: </span><span class="n">p</span><span class="o">.</span><span class="n">f_vector</span><span class="p">()</span>
+<span class="go">(1, 7, 12, 7, 1)</span>
+</pre></div>
+</div>
+</blockquote>
+
+
+</div>
+</html>
+}}}
+
+<p>Here is a picture of the 24-cell projected into 3 dimensions:</p>
+
+{{{id=1|
+cell24.plot()
+///
+}}}
+
+<p><span style="font-weight: normal;"><span style="font-size: medium;">The "round" 24-cell can be $GL(4,\mathbb{Q})$-squished into a lattice polytope:</span></span></p>
+
+{{{id=13|
+cell24 = Polyhedron(vertices=[
+ (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1),
+ (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1),
+ (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0),
+ (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1)])
+cell24.f_vector()
+///
+(1, 24, 96, 96, 24, 1)
+}}}
+
+{{{id=67|
+cell24.lattice_polytope().is_reflexive()
+///
+True
+}}}
+
+<h2>Symmetry groups</h2>
+<p>Here is the symmetry group of the 24-cell</p>
+
+{{{id=27|
+Aut = cell24.restricted_automorphism_group()
+Aut.cardinality()
+///
+1152
+}}}
+
+{{{id=34|
+Aut.gens()
+///
+[(3,9)(4,18)(7,13)(8,14)(10,20)(22,24), (2,3)(6,7)(10,11)(14,15)(17,18)(21,22), (2,4)(3,19)(5,18)(7,10)(8,21)(9,17)(12,22)(14,23)(15,24), (2,18)(3,17)(4,5)(8,23)(9,19)(12,24)(13,20)(14,21)(15,22), (2,19)(3,4)(5,17)(6,11)(8,22)(9,18)(12,21)(14,24)(15,23), (1,2,19,10,12,24,16,15,23,7,5,4)(3,18,20,9,21,11,14,22,13,8,17,6), (1,16)(2,21)(3,22)(4,8)(5,23)(9,24)(12,19)(14,18)(15,17)]
+}}}
+
+<p>Pick the following $G$-permutation action on the vertices of $\nabla$</p>
+
+{{{id=36|
+G = PermutationGroup([
+ '(1,14,22)(2,24,7)(3,18,16)(4,10,15)(5,21,11)(6,12,17)(8,19,13)(9,23,20)',
+ '(1,10,16,7)(2,12,15,5)(3,9,14,8)(4,19,24,23)(6,20,11,13)(17,18,21,22)'])
+G.is_subgroup(Aut) and G.is_isomorphic( SL(2,3).as_matrix_group().as_permutation_group() )
+///
+True
+}}}
+
+{{{id=85|
+G.orbits()
+///
+[[1, 10, 14, 16, 15, 8, 22, 7, 3, 5, 4, 19, 17, 2, 9, 18, 21, 24, 13, 6, 12, 23, 11, 20]]
+}}}
+
+<p>Representatives for the 7 conjugacy classes:</p>
+
+{{{id=44|
+G.conjugacy_classes_representatives()
+///
+[(), (1,2,21,16,15,17)(3,19,10,14,23,7)(4,20,12,24,13,5)(6,8,22,11,9,18), (1,4,8,16,24,9)(2,6,23,15,11,19)(3,20,21,14,13,17)(5,7,22,12,10,18), (1,6,16,11)(2,14,15,3)(4,21,24,17)(5,8,12,9)(7,20,10,13)(18,23,22,19), (1,8,24)(2,23,11)(3,21,13)(4,16,9)(5,22,10)(6,15,19)(7,12,18)(14,17,20), (1,16)(2,15)(3,14)(4,24)(5,12)(6,11)(7,10)(8,9)(13,20)(17,21)(18,22)(19,23), (1,21,15)(2,16,17)(3,10,23)(4,12,13)(5,20,24)(6,22,9)(7,19,14)(8,11,18)]
+}}}
+
+<p>Here is the orbit of $1$ under the permutation $g_3$:</p>
+
+{{{id=52|
+(G.1).orbit(1)
+///
+[1, 14, 22]
+}}}
+
+<h1 style="text-align: center;">The 24-cell toric variety</h1>
+
+{{{id=45|
+fan = FaceFan(cell24.lattice_polytope())
+Pnabla = ToricVariety(FaceFan(cell24.lattice_polytope()),
+ coordinate_names='z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, '+
+ 'z13, z14, z15, z16, z17, z18, z19, z20, z21, z22, z23, z24',
+ base_field=GF(101))
+Pnabla
+///
+4-d toric variety covered by 24 affine patches
+}}}
+
+{{{id=56|
+Pnabla.Chow_group().degree()
+///
+(Z, Z, C2 x C2 x Z^30, Z^20, Z)
+}}}
+
+{{{id=54|
+SR = Pnabla.Stanley_Reisner_ideal(); SR
+///
+Ideal (z2*z11, z4*z11, z5*z11, z6*z11, z8*z11, z11*z14, z11*z18, z11*z21, z11*z23, z1*z12, z4*z12, z5*z12, z6*z12, z7*z12, z12*z13, z12*z17, z12*z18, z12*z23, z1*z15, z2*z15, z4*z15, z6*z15, z10*z15, z15*z18, z15*z19, z15*z20, z15*z21, z1*z16, z2*z16, z3*z16, z4*z16, z5*z16, z9*z16, z16*z17, z16*z18, z16*z19, z1*z22, z2*z22, z5*z22, z6*z22, z9*z22, z10*z22, z13*z22, z14*z22, z18*z22, z1*z24, z2*z24, z3*z24, z4*z24, z5*z24, z6*z24, z7*z24, z8*z24, z20*z24, z3*z10, z4*z10, z5*z10, z7*z10, [...]
+}}}
+
+{{{id=55|
+Pnabla.inject_variables()
+z1*z16 in SR and z1*z14*z22 in SR
+///
+Defining z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15, z16, z17, z18, z19, z20, z21, z22, z23, z24
+True
+}}}
+
+<h1 style="text-align: center;">The Calabi-Yau Hypersurface</h1>
+<p style="text-align: left;">The polynomial $P=P_0+P_\infty$ is</p>
+
+{{{id=57|
+anticanonical_bundle = -Pnabla.K()
+P = sum(anticanonical_bundle.sections_monomials())
+P([1]*24) # g_3 and g_4^2-fixed point z_i=1
+///
+25
+}}}
+
+<p>One of the maximal cones is $\langle p_1,p_2,p_3,p_4,p_{19},p_{20}\rangle$:</p>
+
+{{{id=69|
+cone = fan.generating_cone(8)
+cone.ambient_ray_indices()
+///
+(0, 1, 2, 3, 18, 19)
+}}}
+
+<p>The singularity of $\mathbb{P}_\nabla$ is where the corresponding homogeneous variables vanish:</p>
+
+{{{id=63|
+P(0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1)
+///
+1
+}}}
+
+<h1 style="text-align: center;">Checking Transversality of the Equation</h1>
+<p><span style="font-weight: normal;"><span style="font-size: medium;">The patches are non-complete intersections: 9 equations in $\mathbb{C}^8$ cutting out a $4$-dimensional affine toric variety</span></span></p>
+
+{{{id=71|
+ambient_patch = Pnabla.affine_algebraic_patch(cone, names='x+')
+ambient_patch
+///
+Closed subscheme of Affine Space of dimension 8 over Finite Field of size 101 defined by:
+ -x1*x4 + x0*x7,
+ -x1*x5 + x0*x6,
+ -x4*x6 + x5*x7,
+ x0*x4 - x3*x5,
+ -x2*x4 + x3*x7,
+ -x1*x4 + x3*x6,
+ x0*x2 - x1*x3,
+ x2*x6 - x1*x7,
+ -x1*x4 + x2*x5
+}}}
+
+<p>Of course there is a singularity at $0\in \mathbb{C}^8$:</p>
+
+{{{id=76|
+ambient_patch.is_smooth()
+///
+False
+}}}
+
+<p>Now we throw in the equation $P=0$ and go to the same patch again:</p>
+
+{{{id=70|
+Xtilde = Pnabla.subscheme(P)
+patch = Xtilde.affine_algebraic_patch(cone, names='x+')
+patch
+///
+Closed subscheme of Affine Space of dimension 8 over Finite Field of size 101 defined by:
+ -x1*x4 + x0*x7,
+ -x1*x5 + x0*x6,
+ -x4*x6 + x5*x7,
+ x0*x4 - x3*x5,
+ -x2*x4 + x3*x7,
+ -x1*x4 + x3*x6,
+ x0*x2 - x1*x3,
+ x2*x6 - x1*x7,
+ -x1*x4 + x2*x5,
+ x2^2*x5^2 + x0*x2*x5 + x2^2*x5 + x2*x3*x5 + x2*x4*x5 + x2*x5^2 + x0*x2*x6 + x2*x5*x6 + x2*x5*x7 + x0*x2 + x0*x4 + x2*x4 + x1*x5 + x2*x5 + x2*x6 + x5*x7 + x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + 1
+}}}
+
+{{{id=73|
+patch.is_smooth()
+///
+True
+}}}
+
+{{{id=81|
+
+///
+}}}
\ No newline at end of file
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/worksheet_conf.pickle b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/worksheet_conf.pickle
new file mode 100644
index 0000000..a39bf56
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/10/worksheet_conf.pickle
@@ -0,0 +1,56 @@
+(dp1
+S'tags'
+p2
+(dp3
+S'admin'
+p4
+(lp5
+I0
+asS'guest'
+p6
+(lp7
+I1
+assS'id_number'
+p8
+I10
+sS'pretty_print'
+p9
+I00
+sS'system'
+p10
+S'sage'
+p11
+sS'published_id_number'
+p12
+NsS'owner'
+p13
+S'admin'
+p14
+sS'viewers'
+p15
+(lp16
+sS'ratings'
+p17
+(lp18
+sS'collaborators'
+p19
+(lp20
+sS'name'
+p21
+VOxford Seminar (1,1)-Calabi Yau
+p22
+sS'auto_publish'
+p23
+I00
+sS'last_change'
+p24
+(S'admin'
+p25
+F1297684209.597744
+tp26
+sS'worksheet_that_was_published'
+p27
+(g4
+I10
+tp28
+s.
\ No newline at end of file
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/4/worksheet.html b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/4/worksheet.html
new file mode 100644
index 0000000..3edfbe5
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/4/worksheet.html
@@ -0,0 +1,26 @@
+
+
+<h2>Równanie Newtona</h2>
+<h2>$$\vec F= m\vec a$$ </h2>
+<p>Rzut pionowy</p>
+<p>$$F= m a$$ </p>
+<p> </p>
+<h2> Krok czasowy: $\Delta t$.</h2>
+<p> </p>
+<ul>
+<li>$ v = \displaystyle\frac{ \Delta y}{\Delta t}$</li>
+</ul>
+<ul>
+<li>$ a = \displaystyle \frac{\Delta v}{\Delta t}$</li>
+</ul>
+<div> </div>
+<p>$$\begin{cases} \quad \displaystyle \frac{\Delta y}{\Delta t} &=& v \\ \quad \displaystyle \frac{\Delta v}{\Delta t} &=& \displaystyle \frac { F}{m} \end{cases} $$</p>
+<p> </p>
+<p> </p>
+<div> $\:y_0\:$ i $\:v_{0}\:$</div>
+<p>$$\begin{cases}<br />\quad y &=&y_0\ +\ v_{0}\:\Delta t\\ <br /><br />\quad v &=&v_{0}\ +\ \frac{F}{m}\:\Delta t \end{cases}$$</p>
+
+{{{id=1|
+
+///
+}}}
\ No newline at end of file
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/4/worksheet_conf.pickle b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/4/worksheet_conf.pickle
new file mode 100644
index 0000000..389a427
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/4/worksheet_conf.pickle
@@ -0,0 +1,58 @@
+(dp1
+S'system'
+p2
+S'sage'
+p3
+sS'saved_by_info'
+p4
+(dp5
+sS'tags'
+p6
+(dp7
+S'admin'
+p8
+(lp9
+I1
+assS'id_number'
+p10
+I4
+sS'pretty_print'
+p11
+I00
+sS'live_3D'
+p12
+I00
+sS'published_id_number'
+p13
+NsS'owner'
+p14
+S'admin'
+p15
+sS'viewers'
+p16
+(lp17
+sS'ratings'
+p18
+(lp19
+sS'collaborators'
+p20
+(lp21
+sS'name'
+p22
+VMathJax_problem1
+p23
+sS'auto_publish'
+p24
+I00
+sS'last_change'
+p25
+(S'admin'
+p26
+F1467286221.0016849
+tp27
+sS'worksheet_that_was_published'
+p28
+(g15
+I4
+tp29
+s.
\ No newline at end of file
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/5/worksheet.html b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/5/worksheet.html
new file mode 100644
index 0000000..e69de29
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/5/worksheet_conf.pickle b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/5/worksheet_conf.pickle
new file mode 100644
index 0000000..6a68c39
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/2/21/212/2123/admin/5/worksheet_conf.pickle
@@ -0,0 +1,66 @@
+(dp1
+S'system'
+p2
+S'sage'
+p3
+sS'saved_by_info'
+p4
+(dp5
+sS'tags'
+p6
+(dp7
+Vadmin
+p8
+(lp9
+I1
+asValeksandra.slapik
+p10
+(lp11
+I1
+asVmarcin.kostur
+p12
+(lp13
+I1
+assS'id_number'
+p14
+I44
+sS'pretty_print'
+p15
+I00
+sS'live_3D'
+p16
+I00
+sS'published_id_number'
+p17
+NsS'owner'
+p18
+Valeksandra.slapik
+p19
+sS'viewers'
+p20
+(lp21
+sS'ratings'
+p22
+(lp23
+sS'collaborators'
+p24
+(lp25
+sS'name'
+p26
+VWDI projekt - R�\u017cankowski, Kie\u0142pi\u0144ski, Kozok
+p27
+sS'auto_publish'
+p28
+I00
+sS'last_change'
+p29
+(S'aleksandra.slapik'
+p30
+F1453628866.7567761
+tp31
+sS'worksheet_that_was_published'
+p32
+(g10
+I44
+tp33
+s.
\ No newline at end of file
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/9/9b/9bb/9bbe/_sage_/4/worksheet.html b/test/dot_sage/sage_notebook.sagenb/home/__store__/9/9b/9bb/9bbe/_sage_/4/worksheet.html
new file mode 100644
index 0000000..a7d39db
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/9/9b/9bb/9bbe/_sage_/4/worksheet.html
@@ -0,0 +1,282 @@
+
+
+<div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index" accesskey="I">index</a></li>
+ <li class="right">
+ <a href="py-modindex.html" title="Python Module Index">modules</a> |</li>
+ <li class="right">
+ <a href="introduction.html" title="Introduction" accesskey="N">next</a> |</li>
+
+
+ <a href="../index.html"><img src="_static/sagelogo.png" style="vertical-align: middle" title="Sage Logo"></a>
+
+
+
+ <li><a href="#">Sage Tutorial v6.4.rc1</a> »</li>
+
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body">
+
+ <div class="section" id="welcome-to-the-sage-tutorial">
+<h1>Welcome to the Sage Tutorial!<a class="headerlink" href="#welcome-to-the-sage-tutorial" title="Permalink to this headline">¶</a></h1>
+<p>Sage is free, open-source math software that supports research and
+teaching in algebra, geometry, number theory, cryptography,
+numerical computation, and related areas. Both the Sage development
+model and the technology in Sage itself are distinguished by an
+extremely strong emphasis on openness, community, cooperation, and
+collaboration: we are building the car, not reinventing the wheel.
+The overall goal of Sage is to create a viable, free, open-source
+alternative to Maple, Mathematica, Magma, and MATLAB.</p>
+<p>This tutorial is the best way to become familiar with Sage in only
+a few hours. You can read it in HTML or PDF versions, or from the
+Sage notebook (click <tt class="docutils literal"><span class="pre">Help</span></tt>, then click <tt class="docutils literal"><span class="pre">Tutorial</span></tt> to interactively
+work through the tutorial from within Sage).</p>
+<p>This work is licensed under a <a class="reference external" href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share Alike
+3.0 License</a>.</p>
+<div class="toctree-wrapper compound">
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="introduction.html#installation">Installation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="introduction.html#ways-to-use-sage">Ways to Use Sage</a></li>
+<li class="toctree-l2"><a class="reference internal" href="introduction.html#longterm-goals-for-sage">Longterm Goals for Sage</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="tour.html">A Guided Tour</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="tour_assignment.html">Assignment, Equality, and Arithmetic</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_help.html">Getting Help</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_help.html#functions-indentation-and-counting">Functions, Indentation, and Counting</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_algebra.html">Basic Algebra and Calculus</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_plotting.html">Plotting</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_functions.html">Some Common Issues with Functions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_rings.html">Basic Rings</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_linalg.html">Linear Algebra</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_polynomial.html">Polynomials</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_coercion.html">Parents, Conversion and Coercion</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_groups.html">Finite Groups, Abelian Groups</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_numtheory.html">Number Theory</a></li>
+<li class="toctree-l2"><a class="reference internal" href="tour_advanced.html">Some More Advanced Mathematics</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="interactive_shell.html">The Interactive Shell</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#your-sage-session">Your Sage Session</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#logging-input-and-output">Logging Input and Output</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#paste-ignores-prompts">Paste Ignores Prompts</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#timing-commands">Timing Commands</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#other-ipython-tricks">Other IPython tricks</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#errors-and-exceptions">Errors and Exceptions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#reverse-search-and-tab-completion">Reverse Search and Tab Completion</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#integrated-help-system">Integrated Help System</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#saving-and-loading-individual-objects">Saving and Loading Individual Objects</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#saving-and-loading-complete-sessions">Saving and Loading Complete Sessions</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interactive_shell.html#the-notebook-interface">The Notebook Interface</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Interfaces</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="interfaces.html#gp-pari">GP/PARI</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interfaces.html#gap">GAP</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interfaces.html#singular">Singular</a></li>
+<li class="toctree-l2"><a class="reference internal" href="interfaces.html#maxima">Maxima</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="latex.html">Sage, LaTeX and Friends</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#overview">Overview</a></li>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#basic-use">Basic Use</a></li>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#customizing-latex-generation">Customizing LaTeX Generation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#customizing-latex-processing">Customizing LaTeX Processing</a></li>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#an-example-combinatorial-graphs-with-tkz-graph">An Example: Combinatorial Graphs with tkz-graph</a></li>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#a-fully-capable-tex-installation">A Fully Capable TeX Installation</a></li>
+<li class="toctree-l2"><a class="reference internal" href="latex.html#external-programs">External Programs</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="programming.html">Programming</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#loading-and-attaching-sage-files">Loading and Attaching Sage files</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#creating-compiled-code">Creating Compiled Code</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#standalone-python-sage-scripts">Standalone Python/Sage Scripts</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#data-types">Data Types</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#lists-tuples-and-sequences">Lists, Tuples, and Sequences</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#dictionaries">Dictionaries</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#sets">Sets</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#iterators">Iterators</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#loops-functions-control-statements-and-comparisons">Loops, Functions, Control Statements, and Comparisons</a></li>
+<li class="toctree-l2"><a class="reference internal" href="programming.html#profiling">Profiling</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="sagetex.html">Using SageTeX</a></li>
+<li class="toctree-l1"><a class="reference internal" href="afterword.html">Afterword</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="afterword.html#why-python">Why Python?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="afterword.html#i-would-like-to-contribute-somehow-how-can-i">I would like to contribute somehow. How can I?</a></li>
+<li class="toctree-l2"><a class="reference internal" href="afterword.html#how-do-i-reference-sage">How do I reference Sage?</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="appendix.html">Appendix</a><ul>
+<li class="toctree-l2"><a class="reference internal" href="appendix.html#arithmetical-binary-operator-precedence">Arithmetical binary operator precedence</a></li>
+</ul>
+</li>
+<li class="toctree-l1"><a class="reference internal" href="bibliography.html">Bibliography</a></li>
+</ul>
+</div>
+</div>
+<div class="section" id="indices-and-tables">
+<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h1>
+<ul class="simple">
+<li><a class="reference internal" href="genindex.html"><em>Index</em></a></li>
+<li><a class="reference internal" href="py-modindex.html"><em>Module Index</em></a></li>
+<li><a class="reference internal" href="search.html"><em>Search Page</em></a></li>
+</ul>
+</div>
+
+
+ </div>
+ </div>
+ </div>
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ <h3><a href="#">Table Of Contents</a></h3>
+ <ul>
+<li><a class="reference internal" href="#">Welcome to the Sage Tutorial!</a></li>
+<li><a class="reference internal" href="#indices-and-tables">Indices and tables</a></li>
+</ul>
+
+ <h4>Next topic</h4>
+ <p class="topless"><a href="introduction.html" title="next chapter">Introduction</a></p>
+ <h3>This Page</h3>
+ <ul class="this-page-menu">
+ <li><a href="_sources/index.txt" rel="nofollow">Show Source</a></li>
+ </ul>
+ <div id="searchbox" style="display: none">
+ <h3>Quick search</h3>
+ <p class="searchtip" style="font-size: 90%">
+ Enter search terms or a module, class or function name.
+ </p>
+ </div>
+ <script type="text/javascript">$('#searchbox').show(0);</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="genindex.html" title="General Index">index</a></li>
+ <li class="right">
+ <a href="py-modindex.html" title="Python Module Index">modules</a> |</li>
+ <li class="right">
+ <a href="introduction.html" title="Introduction">next</a> |</li>
+
+
+ <a href="../index.html"><img src="_static/sagelogo.png" style="vertical-align: middle" title="Sage Logo"></a>
+
+
+
+ <li><a href="#">Sage Tutorial v6.4.rc1</a> »</li>
+
+ </ul>
+ </div>
+
+ <div class="footer">
+ © Copyright 2005--2014, The Sage Development Team.
+ Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.2.
+ </div>
+ <script type="text/javascript">
+/*global jQuery, window */
+/* Sphinx sidebar toggle. Putting this code at the end of the body
+ * enables the toggle for the live, static, and offline docs. Note:
+ * sage.misc.html.math_parse() eats jQuery's dollar-sign shortcut. */
+var jq = jQuery;
+jq(document).ready(function () {
+ var bar, bod, bg, fg, key, tog, wid_old, wid_new, resize, get_state, set_state;
+ bod = jq('div.bodywrapper');
+ bar = jq('div.sphinxsidebar');
+ tog = jq('<div class="sphinxsidebartoggle"></div>');
+
+ /* Delayed resize helper. Not perfect but good enough. */
+ resize = function () {
+ setTimeout(function () {
+ tog.height(bod.height());
+ }, 100);
+ };
+ jq(window).resize(function () {
+ resize();
+ });
+
+ /* Setup and add the toggle. See Sphinx v0.5.1 default.css. */
+ fg = jq('div.sphinxsidebar p a').css('color') || 'rgb(152, 219, 204)';
+ bg = jq('div.document').css('background-color') || 'rgb(28, 78, 99)';
+ wid_old = '230px';
+ wid_new = '5px';
+ tog.css('background-color', bg)
+ .css('border-width', '0px')
+ .css('border-right', wid_new + ' ridge ' + bg)
+ .css('cursor', 'pointer')
+ .css('position', 'absolute')
+ .css('left', '-' + wid_new)
+ .css('top', '0px')
+ .css('width', wid_new);
+ bod.css('position', 'relative');
+ bod.prepend(tog);
+ resize();
+
+ /* Cookie helpers. */
+ key = 'sphinxsidebar=';
+ set_state = function (s) {
+ var date = new Date();
+ /* Expiry in 7 days. */
+ date.setTime(date.getTime() + (7 * 24 * 3600 * 1000));
+ document.cookie = key + encodeURIComponent(s) + '; expires=' +
+ date.toUTCString() + '; path=/';
+ };
+ get_state = function () {
+ var i, c, crumbs = document.cookie.split(';');
+ for (i = 0; i < crumbs.length; i += 1) {
+ c = crumbs[i].replace(/^\s+/, '');
+ if (c.indexOf(key) === 0) {
+ return decodeURIComponent(c.substring(key.length, c.length));
+ }
+ }
+ return null;
+ };
+
+ /* Event handlers. */
+ tog.mouseover(function (ev) {
+ tog.css('border-right-color', fg);
+ }).mouseout(function (ev) {
+ tog.css('border-right-color', bg);
+ }).click(function (ev) {
+ if (bod.hasClass('wide')) {
+ bod.removeClass('wide');
+ bod.css('margin-left', wid_old);
+ bar.css('width', wid_old);
+ bar.show();
+ set_state('visible');
+ } else {
+ set_state('hidden');
+ bar.hide();
+ bar.css('width', '0px');
+ bod.css('margin-left', wid_new);
+ bod.addClass('wide');
+ }
+ resize();
+ });
+
+ /* Hide the normally visible sidebar? */
+ if (get_state() === 'hidden') {
+ tog.trigger('click');
+ } else {
+ set_state('visible');
+ }
+});
+ </script>
+
+{{{id=1|
+
+///
+}}}
\ No newline at end of file
diff --git a/test/dot_sage/sage_notebook.sagenb/home/__store__/9/9b/9bb/9bbe/_sage_/4/worksheet_conf.pickle b/test/dot_sage/sage_notebook.sagenb/home/__store__/9/9b/9bb/9bbe/_sage_/4/worksheet_conf.pickle
new file mode 100644
index 0000000..094432c
--- /dev/null
+++ b/test/dot_sage/sage_notebook.sagenb/home/__store__/9/9b/9bb/9bbe/_sage_/4/worksheet_conf.pickle
@@ -0,0 +1,61 @@
+(dp1
+S'system'
+p2
+S'sage'
+p3
+sS'saved_by_info'
+p4
+(dp5
+sS'tags'
+p6
+(dp7
+S'admin'
+p8
+(lp9
+I1
+asS'_sage_'
+p10
+(lp11
+I1
+assS'id_number'
+p12
+I4
+sS'pretty_print'
+p13
+I00
+sS'live_3D'
+p14
+I00
+sS'published_id_number'
+p15
+NsS'owner'
+p16
+S'_sage_'
+p17
+sS'viewers'
+p18
+(lp19
+sS'ratings'
+p20
+(lp21
+sS'collaborators'
+p22
+(lp23
+sS'name'
+p24
+VWelcome to the Sage Tutorial! -- Sage Tutorial v6.4.rc1
+p25
+sS'auto_publish'
+p26
+I00
+sS'last_change'
+p27
+(g10
+F1415283547.06429
+tp28
+sS'worksheet_that_was_published'
+p29
+(g10
+I4
+tp30
+s.
\ No newline at end of file
diff --git a/test/test_sagenb_list.py b/test/test_sagenb_list.py
new file mode 100644
index 0000000..9696c6e
--- /dev/null
+++ b/test/test_sagenb_list.py
@@ -0,0 +1,28 @@
+#
+
+
+import os
+import unittest
+from sagenb_export.sagenb_reader import (
+ NotebookSageNB,
+ TextCell, ComputeCell,
+)
+
+
+DOT_SAGE = os.path.join(os.path.dirname(__file__), 'dot_sage')
+
+class ListSageNB(unittest.TestCase):
+
+ def test_list(self):
+ nbks = list(NotebookSageNB.all_iter(DOT_SAGE))
+ self.assertEqual(len(nbks), 4)
+ sage_4, admin_4, admin_10, aleks = sorted(nbks)
+ self.assertEqual(sage_4.unique_id, '_sage_:4')
+ self.assertEqual(sage_4.name, u'Welcome to the Sage Tutorial! -- Sage Tutorial v6.4.rc1')
+ self.assertEqual(admin_4.unique_id, 'admin:4')
+ self.assertEqual(admin_4.name, u'MathJax_problem1')
+ self.assertEqual(admin_10.unique_id, 'admin:10')
+ self.assertEqual(admin_10.name, u'Oxford Seminar (1,1)-Calabi Yau')
+ self.assertEqual(aleks.unique_id, 'aleksandra.slapik:44')
+ self.assertEqual(aleks.name, u'WDI projekt - R\xf3\u017cankowski, Kie\u0142pi\u0144ski, Kozok')
+
diff --git a/test/test_sagenb_reader.py b/test/test_sagenb_reader.py
new file mode 100644
index 0000000..ada8c88
--- /dev/null
+++ b/test/test_sagenb_reader.py
@@ -0,0 +1,68 @@
+
+import os
+import unittest
+import six
+from sagenb_export.sagenb_reader import (
+ NotebookSageNB,
+ TextCell, ComputeCell,
+)
+
+
+if six.PY2:
+ string_type = unicode
+else:
+ string_type = str
+
+
+DOT_SAGE = os.path.join(os.path.dirname(__file__), 'dot_sage')
+
+
+class ReadSageNB(unittest.TestCase):
+ """
+ Test various sample notebooks
+ """
+
+ def test_admin_10(self):
+ notebook = NotebookSageNB.find(DOT_SAGE, 'admin:10')
+ self.assertEqual(notebook.unique_id, 'admin:10')
+ self.assertEqual(notebook.name, 'Oxford Seminar (1,1)-Calabi Yau')
+ cell = list(notebook.cells)
+ self.assertEqual(len(cell), 37)
+ # First cell
+ self.assertIsInstance(cell[0], TextCell)
+ self.assertEqual(cell[0].input, '<h1 style="text-align: center;">The 24-Cell</h1>')
+ # Second cell
+ self.assertIsInstance(cell[1], ComputeCell)
+ self.assertEqual(cell[1].index, 4)
+ self.assertEqual(
+ cell[1].input,
+ 'cell24 = polytopes.twenty_four_cell()\ncell24.f_vector() # it is self-dual')
+ self.assertEqual(cell[1].output, '(1, 24, 96, 96, 24, 1)')
+
+ def test_sage_4(self):
+ notebook = NotebookSageNB.find(DOT_SAGE, '_sage_:4')
+ self.assertEqual(notebook.unique_id, '_sage_:4')
+ self.assertEqual(notebook.name, 'Welcome to the Sage Tutorial! -- Sage Tutorial v6.4.rc1')
+ cell = list(notebook.cells)
+ self.assertEqual(len(cell), 2)
+ self.assertEqual(type(cell[0].input), string_type)
+ self.assertEqual(type(cell[1].input), string_type)
+ self.assertEqual(type(cell[1].output), string_type)
+
+ def test_admin_4(self):
+ notebook = NotebookSageNB.find(DOT_SAGE, 'admin:4')
+ self.assertEqual(notebook.unique_id, 'admin:4')
+ self.assertEqual(notebook.name, u'MathJax_problem1')
+ cell_list = list(notebook.cells)
+ self.assertEqual(len(cell_list), 2)
+ # First cell
+ cell0 = cell_list[0]
+ self.assertIsInstance(cell0, TextCell)
+ self.assertEqual(cell0.input, u'<h2>R\xf3wnanie Newtona</h2>\n<h2>$$\\vec F= m\\vec a$$\xa0</h2>\n<p>Rzut pionowy</p>\n<p>$$F= m a$$\xa0</p>\n<p>\xa0</p>\n<h2>\xa0Krok czasowy: $\\Delta t$.</h2>\n<p>\xa0</p>\n<ul>\n<li>$ \xa0v\xa0=\xa0\\displaystyle\\frac{ \\Delta \xa0y}{\\Delta t}$</li>\n</ul>\n<ul>\n<li>$ \xa0a\xa0=\xa0 \\displaystyle \\frac{\\Delta \xa0v}{\\Delta t}$</li>\n</ul>\n<div>\xa0</div>\n<p>$$\\begin{cases} \\quad \\displaystyle \\frac{\\Delta y}{\\Delta t} &=& v \\\\ [...]
+ # Second cell
+ cell1 = cell_list[1]
+ self.assertIsInstance(cell1, ComputeCell)
+ self.assertEqual(cell1.index, 1)
+ self.assertEqual(cell1.input, '')
+ self.assertEqual(cell1.output, '')
+
diff --git a/test/test_sagenb_writer.py b/test/test_sagenb_writer.py
new file mode 100644
index 0000000..c1b18a4
--- /dev/null
+++ b/test/test_sagenb_writer.py
@@ -0,0 +1,39 @@
+
+import os
+import unittest
+import tempfile
+import shutil
+from sagenb_export.sagenb_reader import (
+ NotebookSageNB,
+ TextCell, ComputeCell,
+)
+from sagenb_export.ipynb_writer import IpynbWriter
+
+
+DOT_SAGE = os.path.join(os.path.dirname(__file__), 'dot_sage')
+
+
+class ReadSageNB(unittest.TestCase):
+ """
+ Test various sample notebooks
+ """
+
+ def setUp(self):
+ self.tmp = tempfile.mkdtemp(prefix='sagenb_export_')
+
+ def tearDown(self):
+ shutil.rmtree(self.tmp, ignore_errors=True)
+
+ def tmp_filename(self, name):
+ return os.path.join(self.tmp, name)
+
+ def test_sage_4(self):
+ notebook = NotebookSageNB.find(DOT_SAGE, '_sage_:4')
+ ipynb = IpynbWriter(notebook)
+ ipynb.write(self.tmp_filename('sage:4.ipynb'))
+
+ def test_aleksandra_slapik_44(self):
+ notebook = NotebookSageNB.find(DOT_SAGE, 'aleksandra.slapik:44')
+ ipynb = IpynbWriter(notebook)
+ ipynb.write(self.tmp_filename('aleksandra_slapik_44.ipynb'))
+ ipynb.write(self.tmp_filename(u'WDI projekt - R\xf3\u017cankowski, Kie\u0142pi\u0144ski, Kozok.ipynb'))
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..1522bb8
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,12 @@
+[tox]
+envlist = py27, py34
+
+[testenv:py27]
+commands=python2.7 -m unittest discover
+
+[testenv:py34]
+commands=python3.4 -m unittest discover
+
+[testenv:py35]
+commands=python3.5 -m unittest discover
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/sagenb-export.git
More information about the debian-science-commits
mailing list